name: PR Title Check on: pull_request_target: types: [opened, edited, reopened, synchronize] jobs: title-format: if: github.repository == 'AstrBotDevs/AstrBot' runs-on: ubuntu-latest permissions: pull-requests: write issues: write steps: - name: Validate PR title uses: actions/github-script@v9 with: script: | const title = (context.payload.pull_request.title || "").trim(); // Allow Conventional Commit style PR titles. // Examples: // feat: xxx // feat(scope): xxx // fix: xxx // fix(scope): xxx const allowedTypes = "feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert"; const pattern = new RegExp(`^(${allowedTypes})(\\([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`", "- `fix: xxx`", "- `fix(scope): xxx`", "- `chore: xxx`", "", "Allowed prefixes:", "`feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`, `ci`, `build`, `revert`", "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 Conventional Commit format, e.g. feat: xxx, feat(scope): xxx, or fix: xxx."); }