Skip to content

sync-documentation

sync-documentation #87

name: Sync Documentation Receiver
on:
repository_dispatch:
types: [sync-documentation]
permissions:
contents: write
pull-requests: write
jobs:
sync-documentation:
name: Sync Documentation
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Validate input
id: validate
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const payload = context.payload.client_payload || {};
const required = ['artifact-id', 'repository', 'run-id'];
const missing = required.filter(field => !payload[field]);
if (missing.length) {
return core.setFailed(`Missing required inputs: ${missing.join(', ')}`);
}
function sanitizeSegment(segment) {
return segment
.replace(/^[.\s]+/, '')
.replace(/[^a-zA-Z0-9._-]/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '')
.toLowerCase();
}
const repoName = payload.repository.split('/')[1] || payload.repository;
const sanitizedRepoName = sanitizeSegment(repoName);
if(!sanitizedRepoName) {
return core.setFailed(`Unable to sanitize repository ${repoName} name for documentation path.`);
}
const docsPath = `application/docs/projects/${sanitizedRepoName}`;
const staticPath = `application/static/${sanitizedRepoName}`;
core.debug(`Sanitized docs path: ${docsPath}`);
core.setOutput('docs-path', docsPath);
core.debug(`Static asset path: ${staticPath}`);
core.setOutput('static-path', staticPath);
core.debug(`Repository: ${payload.repository}`);
core.setOutput('repository', payload.repository);
core.debug(`Run ID: ${payload['run-id']}`);
core.setOutput('run-id', payload['run-id']);
core.debug(`Artifact ID: ${payload['artifact-id']}`);
core.setOutput('artifact-id', payload['artifact-id']);
- name: Download documentation artifact
id: download-artifact
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
artifact-ids: ${{ steps.validate.outputs['artifact-id'] }}
path: ${{ runner.temp }}/documentation-download-${{ github.run_id }}
repository: ${{ steps.validate.outputs['repository'] }}
run-id: ${{ steps.validate.outputs['run-id'] }}
- name: Prepare documentation content
id: prepare-docs
uses: ./.github/actions/prepare-docs
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
artifact-path: ${{ steps.download-artifact.outputs.download-path }}
source-repository: ${{ steps.validate.outputs['repository'] }}
run-id: ${{ steps.validate.outputs['run-id'] }}
docs-path: ${{ steps.validate.outputs['docs-path'] }}
static-path: ${{ steps.validate.outputs['static-path'] }}
- name: Inject documentation
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
SOURCE_REPOSITORY: ${{ steps.validate.outputs['repository'] }}
DOCS_PATH: ${{ steps.validate.outputs['docs-path'] }}
STATIC_PATH: ${{ steps.validate.outputs['static-path'] }}
PREPARED_DIR: ${{ steps.prepare-docs.outputs.output-path }}
with:
script: |
const fs = require('fs');
const path = require('path');
const sourceRepository = process.env.SOURCE_REPOSITORY;
const docsPath = process.env.DOCS_PATH;
const staticPath = process.env.STATIC_PATH;
const preparedDir = process.env.PREPARED_DIR;
if (!sourceRepository) {
return core.setFailed('Missing source repository from prepare-docs step.');
}
if (!docsPath) {
return core.setFailed('Missing docs path from prepare-docs step.');
}
if (!staticPath) {
return core.setFailed('Missing static path from prepare-docs step.');
}
if (!preparedDir) {
return core.setFailed('Missing prepared directory configuration.');
}
core.info(`Starting documentation injection from ${sourceRepository}`);
if (!fs.existsSync(preparedDir)) {
return core.setFailed('Prepared documentation directory not found.');
}
await io.rmRF(docsPath);
await io.mkdirP(path.dirname(docsPath));
await io.cp(preparedDir, docsPath, { recursive: true });
// Move static assets if present
const staticAssetsSrc = path.join(docsPath, 'static');
if (fs.existsSync(staticAssetsSrc)) {
await io.rmRF(staticPath);
await io.mkdirP(path.dirname(staticPath));
await io.mv(staticAssetsSrc, staticPath);
}
core.info(`Documentation injected into ${docsPath}`);
- name: Generate Documentation
uses: ./.github/actions/generate-docs
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
id: generate_token
with:
app-id: ${{ vars.CI_BOT_APP_ID }}
private-key: ${{ secrets.CI_BOT_APP_PRIVATE_KEY }}
- uses: hoverkraft-tech/ci-github-common/actions/create-and-merge-pull-request@5f11437c716059f30c635f90055060e4ef8b31a0 # 0.28.0
with:
github-token: ${{ steps.generate_token.outputs.token }}
branch: docs/sync-documentation-${{ github.event.client_payload.repository }}
title: "docs(${{ github.event.client_payload.repository }}): update documentation"
body: Update documentation for ${{ github.event.client_payload.repository }}
commit-message: |
docs(${{ github.event.client_payload.repository }}): update documentation
- name: Summary
if: always()
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
STATUS: ${{ job.status }}
SOURCE_REPOSITORY: ${{ steps.validate.outputs['repository'] }}
ARTIFACT_ID: ${{ steps.validate.outputs['artifact-id'] }}
DOCS_PATH: ${{ steps.validate.outputs['docs-path'] }}
STATIC_PATH: ${{ steps.validate.outputs['static-path'] }}
SOURCE_BRANCH: ${{ steps.prepare-docs.outputs.source-branch }}
PROCESSED_FILES: ${{ steps.prepare-docs.outputs.processed-files }}
with:
script: |
const files = process.env.PROCESSED_FILES ? JSON.parse(process.env.PROCESSED_FILES) : [];
const statusText = process.env.STATUS === 'success'
? 'Documentation committed to public-docs'
: 'Error occurred during documentation sync';
const filesSummary = files.length
? `Processed files:\n${files.join('\n')}`
: 'No files were processed.';
const summaryBuilder = core.summary
.addHeading('Documentation Sync Summary', 2)
.addRaw('\n')
.addList([
`Source Repository: ${process.env.SOURCE_REPOSITORY}`,
`Source Branch: ${process.env.SOURCE_BRANCH}`,
`Docs Path: ${process.env.DOCS_PATH}`,
`Static Path: ${process.env.STATIC_PATH}`,
`Processed file(s): ${files.length}`,
`Artifact: ${process.env.ARTIFACT_ID}`,
`Status: ${statusText}`
])
.addRaw('\n');
if (files.length > 0) {
summaryBuilder
.addRaw("Processed files:")
.addList(files);
} else {
summaryBuilder.addRaw("Processed files: no files were processed.");
}
summaryBuilder
.addRaw('\n\n')
.addRaw('Build and deployment will be handled by the push to main workflow.');
await summaryBuilder.write();