diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml new file mode 100644 index 000000000..f905a537b --- /dev/null +++ b/.github/workflows/pr-title-check.yml @@ -0,0 +1,53 @@ +name: PR Title Check + +on: + pull_request_target: + types: [opened, edited, reopened, synchronize] + +jobs: + title-format: + runs-on: ubuntu-latest + permissions: + pull-requests: write + issues: write + + steps: + - name: Validate PR title + uses: actions/github-script@v7 + with: + script: | + const title = (context.payload.pull_request.title || "").trim(); + // allow only: + // feat: xxx + // feat(scope): xxx + const pattern = /^(feat)(\([a-z0-9-]+\))?:\s.+$/i; + const isValid = pattern.test(title); + const isSameRepo = + context.payload.pull_request.head.repo.full_name === context.payload.repository.full_name; + + if (!isValid) { + if (isSameRepo) { + try { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + body: [ + "⚠️ PR title format check failed.", + "Required formats:", + "- `feat: xxx`", + "- `feat(scope): xxx`", + "Please update your PR title and push again." + ].join("\n") + }); + } catch (e) { + core.warning(`Failed to post PR title comment: ${e.message}`); + } + } else { + core.warning("Fork PR: comment permission is restricted; skip posting review comment."); + } + } + + if (!isValid) { + core.setFailed("Invalid PR title. Expected format: feat: xxx or feat(scope): xxx."); + }