Skip to content

feat(catalog)!: add staged provider catalog indexing #107

feat(catalog)!: add staged provider catalog indexing

feat(catalog)!: add staged provider catalog indexing #107

name: CQ / PR Title
on:
pull_request_target:
types:
- opened
- edited
- reopened
- synchronize
permissions:
contents: read
issues: write
concurrency:
group: pr-title-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
validate-title:
name: Conventional Commit Title
runs-on: ubuntu-latest
steps:
- name: Validate pull request title
id: validate
continue-on-error: true
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
set -euo pipefail
pattern='^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\([a-z0-9._/-]+\))?(!)?: .+$'
if [[ "${PR_TITLE}" =~ ${pattern} ]]; then
echo "PR title is valid: ${PR_TITLE}"
echo "reason=" >> "${GITHUB_OUTPUT}"
exit 0
fi
reason="The title does not match \`type(scope): description\`."
invalid_scope_pattern='^[a-z]+\([^)]*[,[:space:]][^)]*\)'
if [[ ! "${PR_TITLE}" =~ ^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test) ]]; then
reason="The title must start with an allowed lowercase type."
elif [[ "${PR_TITLE}" =~ ${invalid_scope_pattern} ]]; then
reason="The scope must be one lowercase token; commas and spaces are not allowed."
elif [[ ! "${PR_TITLE}" =~ ^[^:]+:\ .+ ]]; then
reason="The header must contain a colon followed by one space and a description."
fi
echo "reason=${reason}" >> "${GITHUB_OUTPUT}"
echo "Pull request title must follow Conventional Commits."
echo "Received: ${PR_TITLE}"
echo
echo "Expected format:"
echo " type(scope): description"
echo " type: description"
echo " type(scope)!: description"
echo
echo "Allowed types:"
echo " build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test"
echo
echo "Examples:"
echo " feat(api): add torrent health endpoint"
echo " fix: handle missing provider aliases"
echo " refactor(parser)!: remove legacy AniWorld slug fallback"
exit 1
- name: Sync pull request guidance comment
if: always()
uses: actions/github-script@v9
env:
COMMENT_MARKER: "<!-- anibridge-pr-title-conventional -->"
PR_TITLE: ${{ github.event.pull_request.title }}
FAILURE_REASON: ${{ steps.validate.outputs.reason }}
with:
script: |
const { owner, repo } = context.repo;
const issue_number = context.payload.pull_request.number;
const marker = process.env.COMMENT_MARKER;
const body = [
marker,
'### Pull request title needs attention',
'',
'**Received:**',
'```text',
process.env.PR_TITLE,
'```',
'',
`**Why it failed:** ${process.env.FAILURE_REASON}`,
'',
'**Expected:** `type(scope): description` or `type: description`',
'',
'Allowed types: `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test`.',
'',
'Examples:',
'- `feat(api): add torrent health endpoint`',
'- `fix: handle missing provider aliases`',
'- `refactor(parser)!: remove legacy AniWorld slug fallback`',
'',
'[Conventional Commits reference](https://www.conventionalcommits.org/en/v1.0.0/)',
].join('\n');
const shouldComment = '${{ steps.validate.outcome }}' === 'failure';
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number,
per_page: 100,
});
const existing = comments.find((comment) =>
comment.user?.type === 'Bot' && comment.body?.includes(marker),
);
if (shouldComment) {
if (existing) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body,
});
}
return;
}
if (existing) {
await github.rest.issues.deleteComment({
owner,
repo,
comment_id: existing.id,
});
}
- name: Enforce title validation
if: steps.validate.outcome == 'failure'
run: exit 1