mirror of https://github.com/abpframework/abp.git
csharpabpc-sharpframeworkblazoraspnet-coredotnet-coreaspnetcorearchitecturesaasdomain-driven-designangularmulti-tenancy
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
8.4 KiB
221 lines
8.4 KiB
# Validates Scriban template syntax in PR-changed Markdown files under docs/en/,
|
|
# so escape issues are caught before they reach the published documentation.
|
|
|
|
name: Check Docs Syntax
|
|
|
|
on:
|
|
pull_request:
|
|
paths:
|
|
- 'docs/en/**/*.md'
|
|
- 'docs/en/docs-params.json'
|
|
- '.github/scripts/CheckDocsSyntax/**'
|
|
- '.github/workflows/check-docs-syntax.yml'
|
|
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
|
|
jobs:
|
|
check-scriban-syntax:
|
|
name: Validate Scriban syntax in docs/en
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup .NET
|
|
uses: actions/setup-dotnet@v4
|
|
with:
|
|
dotnet-version: '10.0.x'
|
|
|
|
- name: Build syntax checker
|
|
run: dotnet build .github/scripts/CheckDocsSyntax/CheckDocsSyntax.csproj -c Release --nologo -v minimal
|
|
|
|
- name: Get changed markdown files
|
|
id: changed
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const prNumber = context.payload.pull_request.number;
|
|
const changed = [];
|
|
let paramsChanged = false;
|
|
let page = 1;
|
|
while (true) {
|
|
const { data: files } = await github.rest.pulls.listFiles({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
pull_number: prNumber,
|
|
per_page: 100,
|
|
page,
|
|
});
|
|
const PARAMS_PATH = 'docs/en/docs-params.json';
|
|
for (const f of files) {
|
|
const isMutation =
|
|
f.status === 'added' || f.status === 'modified' || f.status === 'renamed';
|
|
if (!isMutation) continue;
|
|
// For renames, GitHub puts the new path in `filename` and the
|
|
// old one in `previous_filename`. Detect docs-params.json on
|
|
// either side so renames into / out of that path still trigger
|
|
// the parameter-file validation path.
|
|
if (f.filename === PARAMS_PATH || f.previous_filename === PARAMS_PATH) {
|
|
paramsChanged = true;
|
|
}
|
|
if (f.filename.startsWith('docs/en/') && f.filename.endsWith('.md')) {
|
|
changed.push(f.filename);
|
|
}
|
|
}
|
|
if (files.length < 100) break;
|
|
page++;
|
|
}
|
|
core.setOutput('files', changed.join('\n'));
|
|
core.setOutput('count', changed.length.toString());
|
|
core.setOutput('paramsChanged', paramsChanged ? 'true' : 'false');
|
|
core.info(`Markdown files to check: ${changed.length}`);
|
|
core.info(`docs-params.json changed: ${paramsChanged}`);
|
|
for (const f of changed) {
|
|
core.info(` - ${f}`);
|
|
}
|
|
|
|
- name: Run syntax checker
|
|
id: checker
|
|
if: steps.changed.outputs.count != '0' || steps.changed.outputs.paramsChanged == 'true'
|
|
env:
|
|
CHANGED_FILES: ${{ steps.changed.outputs.files }}
|
|
PARAMS_CHANGED: ${{ steps.changed.outputs.paramsChanged }}
|
|
run: |
|
|
mapfile -t files <<< "$CHANGED_FILES"
|
|
args=()
|
|
for f in "${files[@]}"; do
|
|
if [ -n "$f" ] && [ -f "$f" ]; then
|
|
args+=("$f")
|
|
fi
|
|
done
|
|
|
|
if [ ${#args[@]} -eq 0 ]; then
|
|
if [ "$PARAMS_CHANGED" = "true" ] && [ -f "docs/en/index.md" ]; then
|
|
# No markdown changed, but docs-params.json did. Run the checker
|
|
# against a single known-clean page so BuildRenderParameters /
|
|
# docs-params.json parsing actually executes and fails fast on a
|
|
# malformed parameter file.
|
|
echo "docs-params.json changed but no markdown changed; validating params via docs/en/index.md."
|
|
args+=("docs/en/index.md")
|
|
else
|
|
echo "No existing markdown files to check (all changes are deletions)."
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
# Capture the checker's stdout so a follow-up step can post it as a PR
|
|
# comment when the run fails, while still streaming it to the job log.
|
|
set -o pipefail
|
|
dotnet run --project .github/scripts/CheckDocsSyntax/CheckDocsSyntax.csproj \
|
|
-c Release --no-build -- "${args[@]}" 2>&1 | tee checker-output.txt
|
|
|
|
- name: Upsert PR comment on failure
|
|
if: failure() && steps.checker.conclusion == 'failure'
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const fs = require('fs');
|
|
const MARKER = '<!-- check-docs-syntax-bot -->';
|
|
const prNumber = context.payload.pull_request.number;
|
|
|
|
let report = '';
|
|
try {
|
|
report = fs.readFileSync('checker-output.txt', 'utf8').trim();
|
|
} catch (e) {
|
|
report = '(checker output was not captured)';
|
|
}
|
|
|
|
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
|
|
const body = [
|
|
MARKER,
|
|
'### Docs syntax check failed',
|
|
'',
|
|
'The Scriban syntax checker reported issues in the Markdown files this PR changes. Wrap inline Scriban-looking text with `{%{{{ ... }}}%}` or wrap whole code blocks with `{%{` ... `}%}` to keep it from being parsed as a template.',
|
|
'',
|
|
'<details><summary>Checker output</summary>',
|
|
'',
|
|
'```',
|
|
report,
|
|
'```',
|
|
'',
|
|
'</details>',
|
|
'',
|
|
`[Full run log](${runUrl})`,
|
|
].join('\n');
|
|
|
|
// Find an existing bot comment to update (idempotent across re-runs).
|
|
let existing = null;
|
|
for (let page = 1; ; page++) {
|
|
const { data } = await github.rest.issues.listComments({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
per_page: 100,
|
|
page,
|
|
});
|
|
existing = data.find(c => c.body && c.body.startsWith(MARKER));
|
|
if (existing || data.length < 100) break;
|
|
}
|
|
|
|
if (existing) {
|
|
await github.rest.issues.updateComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
comment_id: existing.id,
|
|
body,
|
|
});
|
|
core.info(`Updated existing bot comment (#${existing.id}).`);
|
|
} else {
|
|
const { data: created } = await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
body,
|
|
});
|
|
core.info(`Created bot comment (#${created.id}).`);
|
|
}
|
|
|
|
- name: Resolve previous failure comment on success
|
|
# Clear any stale failure comment whenever this workflow run is green,
|
|
# even if the syntax checker step was skipped (e.g. when a later
|
|
# commit reverts the earlier failure so no markdown files appear in
|
|
# the PR's net diff).
|
|
if: success()
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const MARKER = '<!-- check-docs-syntax-bot -->';
|
|
const prNumber = context.payload.pull_request.number;
|
|
|
|
for (let page = 1; ; page++) {
|
|
const { data } = await github.rest.issues.listComments({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
per_page: 100,
|
|
page,
|
|
});
|
|
|
|
const existing = data.find(c => c.body && c.body.startsWith(MARKER));
|
|
if (existing) {
|
|
const body = [
|
|
MARKER,
|
|
'### Docs syntax check passed',
|
|
'',
|
|
'The previously reported issues are no longer present in this PR.',
|
|
].join('\n');
|
|
await github.rest.issues.updateComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
comment_id: existing.id,
|
|
body,
|
|
});
|
|
core.info(`Cleared bot comment (#${existing.id}).`);
|
|
break;
|
|
}
|
|
|
|
if (data.length < 100) break;
|
|
}
|
|
|