From 7f6d297334ad543e00bc694e0a560316d4603a25 Mon Sep 17 00:00:00 2001 From: Andrei Cojocaru Date: Wed, 25 Feb 2026 20:33:49 -0500 Subject: [PATCH 1/4] ci: use shared PR validation action from shared-ai-standards Replace inline title regex check with shared `andreiships/shared-ai-standards/.github/actions/pr-validation@main` composite action. Linked issue check and label management remain local. --- .github/workflows/pr-standards.yml | 32 +++++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/.github/workflows/pr-standards.yml b/.github/workflows/pr-standards.yml index 1edbd5d061d..0de437c4462 100644 --- a/.github/workflows/pr-standards.yml +++ b/.github/workflows/pr-standards.yml @@ -11,8 +11,17 @@ jobs: contents: read pull-requests: write steps: - - name: Check PR standards + - name: Validate PR Title + id: title-check + continue-on-error: true + uses: andreiships/shared-ai-standards/.github/actions/pr-validation@main + with: + title-types: feat,fix,docs,chore,refactor,test + + - name: Manage PR labels and check linked issue uses: actions/github-script@v7 + env: + TITLE_OUTCOME: ${{ steps.title-check.outcome }} with: script: | const pr = context.payload.pull_request; @@ -41,6 +50,7 @@ jobs: } const title = pr.title; + const titlePassed = process.env.TITLE_OUTCOME === 'success'; async function addLabel(label) { await github.rest.issues.addLabels({ @@ -71,10 +81,10 @@ jobs: repo: context.repo.repo, issue_number: pr.number }); - - const existing = comments.find(c => c.body.includes(markerText)); + + const existing = comments.find(c => c.body?.includes(markerText)); if (existing) return; - + await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, @@ -83,12 +93,8 @@ jobs: }); } - // Step 1: Check title format - // Matches: feat:, feat(scope):, feat (scope):, etc. - const titlePattern = /^(feat|fix|docs|chore|refactor|test)\s*(\([a-zA-Z0-9-]+\))?\s*:/; - const hasValidTitle = titlePattern.test(title); - - if (!hasValidTitle) { + // Title validation (shared action handles regex, we manage labels/comments) + if (!titlePassed) { await addLabel('needs:title'); await comment('title', `Hey! Your PR title \`${title}\` doesn't follow conventional commit format. @@ -103,13 +109,14 @@ jobs: Where \`scope\` is the package name (e.g., \`app\`, \`desktop\`, \`opencode\`). See [CONTRIBUTING.md](../blob/dev/CONTRIBUTING.md#pr-titles) for details.`); + core.setFailed('PR title does not follow conventional commit format'); return; } await removeLabel('needs:title'); - // Step 2: Check for linked issue (skip for docs/refactor/feat PRs) - const skipIssueCheck = /^(docs|refactor|feat)\s*(\([a-zA-Z0-9-]+\))?\s*:/.test(title); + // Check for linked issue (skip for docs/refactor PRs) + const skipIssueCheck = /^(docs|refactor)\s*(\([a-zA-Z0-9-]+\))?\s*:/.test(title); if (skipIssueCheck) { await removeLabel('needs:issue'); console.log('Skipping issue check for docs/refactor/feat PR'); @@ -146,6 +153,7 @@ jobs: 2. Add \`Fixes #\` or \`Closes #\` to this PR description See [CONTRIBUTING.md](../blob/dev/CONTRIBUTING.md#issue-first-policy) for details.`); + core.setFailed('PR must have a linked issue'); return; } From e3e40f40e598735b6e002b903f33743d82d5d886 Mon Sep 17 00:00:00 2001 From: Andrei Cojocaru Date: Wed, 25 Feb 2026 21:36:35 -0500 Subject: [PATCH 2/4] fix: correct stale log message (docs/refactor only, not feat) --- .github/workflows/pr-standards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-standards.yml b/.github/workflows/pr-standards.yml index 0de437c4462..6986c103087 100644 --- a/.github/workflows/pr-standards.yml +++ b/.github/workflows/pr-standards.yml @@ -119,7 +119,7 @@ jobs: const skipIssueCheck = /^(docs|refactor)\s*(\([a-zA-Z0-9-]+\))?\s*:/.test(title); if (skipIssueCheck) { await removeLabel('needs:issue'); - console.log('Skipping issue check for docs/refactor/feat PR'); + console.log('Skipping issue check for docs/refactor PR'); return; } const query = ` From a46f4da2b23f5d9514805e0273de35a8c83f99a0 Mon Sep 17 00:00:00 2001 From: Andrei Cojocaru Date: Wed, 25 Feb 2026 21:37:04 -0500 Subject: [PATCH 3/4] fix: treat skipped/cancelled title-check outcome as pass to avoid false positives --- .github/workflows/pr-standards.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-standards.yml b/.github/workflows/pr-standards.yml index 6986c103087..8d7c099bfca 100644 --- a/.github/workflows/pr-standards.yml +++ b/.github/workflows/pr-standards.yml @@ -50,7 +50,10 @@ jobs: } const title = pr.title; - const titlePassed = process.env.TITLE_OUTCOME === 'success'; + // 'success' = title valid; 'failure' = title invalid OR infra error (network/action fetch); + // 'skipped'/'cancelled' = step didn't run — treat as unknown (pass to avoid false positives) + const titleOutcome = process.env.TITLE_OUTCOME; + const titlePassed = titleOutcome === 'success' || titleOutcome === 'skipped' || titleOutcome === 'cancelled'; async function addLabel(label) { await github.rest.issues.addLabels({ From 02a78b19dac826849d24022b2ffb1468246723ba Mon Sep 17 00:00:00 2001 From: Andrei Cojocaru Date: Wed, 25 Feb 2026 21:37:27 -0500 Subject: [PATCH 4/4] fix: pin shared-ai-standards action to SHA instead of mutable @main --- .github/workflows/pr-standards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-standards.yml b/.github/workflows/pr-standards.yml index 8d7c099bfca..e844530c552 100644 --- a/.github/workflows/pr-standards.yml +++ b/.github/workflows/pr-standards.yml @@ -14,7 +14,7 @@ jobs: - name: Validate PR Title id: title-check continue-on-error: true - uses: andreiships/shared-ai-standards/.github/actions/pr-validation@main + uses: andreiships/shared-ai-standards/.github/actions/pr-validation@4a7766058a3981a4cd54b440c594aae1d8121c77 # main with: title-types: feat,fix,docs,chore,refactor,test