refactor(cli)!: run forge db on grove instead of the database extension #111
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: PR Conventional Commits Check | |
| on: | |
| pull_request: | |
| branches: [main] | |
| types: [opened, synchronize, reopened, edited] | |
| jobs: | |
| validate-commits: | |
| runs-on: ubuntu-latest | |
| # Skip validation for Release Please PRs (auto-generated) | |
| if: | | |
| !startsWith(github.event.pull_request.title, 'chore(main): release') && | |
| !contains(github.event.pull_request.labels.*.name, 'autorelease: pending') | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| statuses: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: '24' | |
| - name: Cache npm dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.npm | |
| key: ${{ runner.os }}-commitlint-${{ hashFiles('.github/workflows/pr-conventional-commits.yml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-commitlint- | |
| - name: Install Commitlint | |
| run: npm install --save-dev @commitlint/config-conventional @commitlint/cli | |
| - name: Create Commitlint Config | |
| run: | | |
| cat > commitlint.config.js << 'EOF' | |
| module.exports = { | |
| extends: ['@commitlint/config-conventional'], | |
| rules: { | |
| 'type-enum': [2, 'always', [ | |
| 'build', 'chore', 'ci', 'docs', 'feat', 'fix', | |
| 'perf', 'refactor', 'revert', 'style', 'test' | |
| ]], | |
| 'subject-case': [2, 'never', ['start-case', 'pascal-case', 'upper-case']], | |
| 'subject-max-length': [2, 'always', 100], | |
| 'body-max-line-length': [2, 'always', 100], | |
| 'footer-max-line-length': [2, 'always', 100] | |
| } | |
| } | |
| EOF | |
| - name: Check PR Title | |
| id: check_title | |
| env: | |
| PR_TITLE: ${{ github.event.pull_request.title }} | |
| run: | | |
| echo "Checking PR title: $PR_TITLE" | |
| if echo "$PR_TITLE" | npx commitlint; then | |
| echo "title_valid=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "title_valid=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Check PR Commits | |
| id: check_commits | |
| run: | | |
| COMMITS=$(git rev-list --reverse ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}) | |
| COMMIT_COUNT=$(echo "$COMMITS" | wc -l) | |
| VALID=0 | |
| INVALID="" | |
| for commit in $COMMITS; do | |
| MSG=$(git log --format=%B -n 1 "$commit" | head -n 1) | |
| if echo "$MSG" | npx commitlint 2>/dev/null; then | |
| VALID=$((VALID + 1)) | |
| else | |
| INVALID="$INVALID\n- \`${commit:0:7}\`: $MSG" | |
| fi | |
| done | |
| echo "commit_count=$COMMIT_COUNT" >> "$GITHUB_OUTPUT" | |
| echo "valid_commits=$VALID" >> "$GITHUB_OUTPUT" | |
| if [ "$VALID" -eq "$COMMIT_COUNT" ]; then | |
| echo "commits_valid=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "commits_valid=false" >> "$GITHUB_OUTPUT" | |
| { | |
| echo "invalid_commits<<EOF" | |
| echo -e "$INVALID" | |
| echo "EOF" | |
| } >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Update PR comment | |
| if: always() | |
| # Reporting only. A GitHub API 5xx here says nothing about the commits, | |
| # so it must not turn the job red -- "Final validation" below is the | |
| # gate, and it reads the check outputs rather than the API. | |
| continue-on-error: true | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Pass values via env (data, not code) so special chars like | |
| # backticks in commit messages are never evaluated by the shell. | |
| TITLE_VALID: ${{ steps.check_title.outputs.title_valid }} | |
| COMMITS_VALID: ${{ steps.check_commits.outputs.commits_valid }} | |
| COMMIT_COUNT: ${{ steps.check_commits.outputs.commit_count }} | |
| INVALID_COMMITS: ${{ steps.check_commits.outputs.invalid_commits }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| REPO: ${{ github.repository }} | |
| run: | | |
| BODY="## Conventional Commits Validation\n\n" | |
| if [ "$TITLE_VALID" = "true" ]; then | |
| BODY="${BODY}**PR Title**: valid\n" | |
| else | |
| BODY="${BODY}**PR Title**: invalid — please use \`type(scope): description\`\n" | |
| fi | |
| if [ "$COMMITS_VALID" = "true" ]; then | |
| BODY="${BODY}**Commits**: all ${COMMIT_COUNT} follow conventional format\n" | |
| else | |
| BODY="${BODY}**Commits**: some do not follow conventional format\n" | |
| BODY="${BODY}${INVALID_COMMITS}\n" | |
| fi | |
| if [ "$TITLE_VALID" != "true" ] || \ | |
| [ "$COMMITS_VALID" != "true" ]; then | |
| BODY="${BODY}\n### Format\n\n\`type(scope): description\`\n\n" | |
| BODY="${BODY}**Types**: \`feat\`, \`fix\`, \`docs\`, \`style\`, \`refactor\`, \`test\`, \`chore\`, \`ci\`, \`build\`, \`perf\`, \`revert\`\n" | |
| fi | |
| COMMENT_ID=$(gh pr view "$PR_NUMBER" --json comments \ | |
| --jq '.comments[] | select(.author.login == "github-actions[bot]" and (.body | test("Conventional Commits Validation"))) | .id' \ | |
| | head -n 1) | |
| if [ -n "$COMMENT_ID" ]; then | |
| gh api -X PATCH "repos/${REPO}/issues/comments/$COMMENT_ID" \ | |
| -f body="$(echo -e "$BODY")" | |
| else | |
| gh pr comment "$PR_NUMBER" --body "$(echo -e "$BODY")" | |
| fi | |
| - name: Set commit status | |
| if: always() | |
| # Same reasoning as the comment step: these statuses duplicate the job's | |
| # own conclusion, so losing them to a 5xx is cosmetic. | |
| continue-on-error: true | |
| run: | | |
| SHA="${{ github.event.pull_request.head.sha }}" | |
| # The statuses endpoint returns 503 during GitHub API degradation. | |
| # Back off and retry rather than reporting nothing on the first blip. | |
| post_status() { | |
| for attempt in 1 2 3; do | |
| if gh api -X POST "repos/${{ github.repository }}/statuses/$SHA" \ | |
| -f state="$1" -f context="$2" -f description="$3"; then | |
| return 0 | |
| fi | |
| sleep $((attempt * 5)) | |
| done | |
| echo "could not set status $2 after 3 attempts" | |
| return 1 | |
| } | |
| title_state="success" | |
| title_desc="PR title follows conventional commits" | |
| if [ "${{ steps.check_title.outputs.title_valid }}" != "true" ]; then | |
| title_state="failure" | |
| title_desc="PR title does not follow conventional commits" | |
| fi | |
| commits_state="success" | |
| commits_desc="All commits follow conventional commits" | |
| if [ "${{ steps.check_commits.outputs.commits_valid }}" != "true" ]; then | |
| commits_state="failure" | |
| commits_desc="Some commits do not follow conventional commits" | |
| fi | |
| # Each is attempted even if the other gave up, so a partial outage | |
| # still reports what it can. | |
| failed=0 | |
| post_status "$title_state" "conventional-commits/title" "$title_desc" || failed=1 | |
| post_status "$commits_state" "conventional-commits/commits" "$commits_desc" || failed=1 | |
| exit "$failed" | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Label PR | |
| # Labels are cosmetic as well. With the two steps above no longer fatal | |
| # this one actually runs on a degraded API, so it needs the same | |
| # treatment or it becomes the new way a valid PR goes red. | |
| continue-on-error: true | |
| uses: bcoe/conventional-release-labels@v1 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Final validation | |
| run: | | |
| if [ "${{ steps.check_title.outputs.title_valid }}" = "true" ] && \ | |
| [ "${{ steps.check_commits.outputs.commits_valid }}" = "true" ]; then | |
| echo "All conventional commits validations passed" | |
| else | |
| echo "Conventional commits validation failed" | |
| exit 1 | |
| fi |