-
Notifications
You must be signed in to change notification settings - Fork 0
feat(ci): add centralized reusable CI/CD workflows for the reqstool org #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 7 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
0080323
feat(ci): add centralized reusable release and publish workflows
jimisola 50ac417
feat(ci): add centralized build and lint workflows for java, python, …
jimisola fdbd76c
feat(ci): add centralized publish-to-github-pages workflow
jimisola f03f2ff
fix(ci): resolve shellcheck warnings in workflow scripts
jimisola 140fe68
fix(ci): configure act default image to avoid interactive prompt
jimisola 0b5041a
fix(ci): pass workflow_call inputs via event payload, not --input flag
jimisola aab64e7
fix(ci): remove act tests for release and release-preview workflows
jimisola a88ee09
fix(ci): use npm run format --if-present to support repos without for…
jimisola a23bd8b
fix(ci): add explicit permissions: contents: read to ci.yml
jimisola File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| [changelog] | ||
| header = "" | ||
| body = """ | ||
| {% for group, commits in commits | group_by(attribute="group") %}\ | ||
| ### {{ group | upper_first }} | ||
| {% for commit in commits %}\ | ||
| - {{ commit.message | upper_first }}{% if commit.remote.pr_number %} (#{{ commit.remote.pr_number }}){% endif %} | ||
|
|
||
| {% endfor %}\ | ||
| {% endfor %}\ | ||
| """ | ||
| trim = true | ||
| footer = "" | ||
|
|
||
| [git] | ||
| conventional_commits = true | ||
| filter_unconventional = true | ||
| commit_parsers = [ | ||
| { message = "^feat", group = "Features" }, | ||
| { message = "^fix", group = "Bug Fixes" }, | ||
| { message = "^perf", group = "Performance" }, | ||
| { message = "^refactor", group = "Refactoring" }, | ||
| { message = "^chore", group = "Miscellaneous" }, | ||
| { message = "^docs", group = "Documentation" }, | ||
| { message = "^test", group = "Testing" }, | ||
| { message = "^security", group = "Security" }, | ||
| { message = "^style", group = "Style" }, | ||
| { message = "^ci", group = "CI/CD", skip = true }, | ||
| { message = "^build", group = "Build", skip = true }, | ||
| ] | ||
| filter_commits = false | ||
| tag_pattern = "[0-9].*" | ||
| sort_commits = "newest" |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| name: CI | ||
|
|
||
| on: | ||
| push: | ||
| paths: | ||
| - ".github/workflows/**" | ||
| - "tests/**" | ||
| pull_request: | ||
| paths: | ||
| - ".github/workflows/**" | ||
| - "tests/**" | ||
|
|
||
| jobs: | ||
| lint: | ||
| name: Lint workflows | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Install actionlint | ||
| run: | | ||
| VERSION="1.7.7" | ||
| curl -fsSL \ | ||
| "https://github.com/rhysd/actionlint/releases/download/v${VERSION}/actionlint_${VERSION}_linux_amd64.tar.gz" \ | ||
| | tar -xz actionlint | ||
| sudo mv actionlint /usr/local/bin/ | ||
|
|
||
| - name: Install zizmor | ||
| run: pip install zizmor | ||
|
|
||
| - name: Install yamllint | ||
| run: pip install yamllint | ||
|
|
||
| - name: actionlint | ||
| run: actionlint .github/workflows/**/*.yml .github/workflows/*.yml | ||
|
|
||
| - name: zizmor | ||
| run: zizmor --format sarif .github/workflows/ > zizmor.sarif || true | ||
|
|
||
| - name: yamllint | ||
| run: | | ||
| yamllint -d "{extends: relaxed, rules: {line-length: {max: 200}}}" \ | ||
| .github/workflows/ | ||
|
|
||
| test-check-release: | ||
Check warningCode scanning / CodeQL Workflow does not contain permissions Medium
Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
|
||
| name: Test — common/check-release | ||
| needs: lint | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| fixture: | ||
| - valid-semver | ||
| - invalid-semver | ||
| - valid-pep440 | ||
| - invalid-pep440 | ||
| - valid-maven | ||
| - not-a-tag | ||
| - wrong-branch | ||
| - hotfix-branch | ||
| - release-branch | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Install act | ||
| run: | | ||
| VERSION="0.2.74" | ||
| curl -fsSL \ | ||
| "https://github.com/nektos/act/releases/download/v${VERSION}/act_Linux_x86_64.tar.gz" \ | ||
| | tar -xz act | ||
| sudo mv act /usr/local/bin/ | ||
| mkdir -p ~/.config/act | ||
| echo "-P ubuntu-latest=node:20-bullseye-slim" > ~/.config/act/actrc | ||
|
|
||
| - name: Read fixture | ||
| id: fixture | ||
| run: | | ||
| FIXTURE="tests/common/check-release/${{ matrix.fixture }}.json" | ||
| EXPECTED=$(jq -r '.expected_exit' "$FIXTURE") | ||
| GITHUB_REF=$(jq -r '.github_ref' "$FIXTURE") | ||
| VERSION_FORMAT=$(jq -r '.inputs["version-format"]' "$FIXTURE") | ||
| TARGET_COMMITISH=$(jq -r '.event.release.target_commitish' "$FIXTURE") | ||
| { | ||
| echo "expected=$EXPECTED" | ||
| echo "github_ref=$GITHUB_REF" | ||
| echo "version_format=$VERSION_FORMAT" | ||
| echo "target_commitish=$TARGET_COMMITISH" | ||
| } >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Build event payload | ||
| run: | | ||
| jq -n \ | ||
| --arg commitish "${{ steps.fixture.outputs.target_commitish }}" \ | ||
| --arg fmt "${{ steps.fixture.outputs.version_format }}" \ | ||
| '{"release": {"target_commitish": $commitish}, "inputs": {"version-format": $fmt}}' \ | ||
| > /tmp/event.json | ||
|
|
||
| - name: Run act | ||
| id: act | ||
| continue-on-error: true | ||
| run: | | ||
| REF="${{ steps.fixture.outputs.github_ref }}" | ||
| REF_NAME=$(echo "$REF" | sed 's|refs/tags/||;s|refs/heads/||') | ||
| act workflow_call \ | ||
| -W .github/workflows/common/check-release.yml \ | ||
| --eventpath /tmp/event.json \ | ||
| --env "GITHUB_REF=$REF" \ | ||
| --env "GITHUB_REF_NAME=$REF_NAME" \ | ||
| --no-cache-server \ | ||
| -q | ||
|
|
||
| - name: Assert outcome | ||
| run: | | ||
| ACT_EXIT=${{ steps.act.outcome == 'success' && '0' || '1' }} | ||
| EXPECTED="${{ steps.fixture.outputs.expected }}" | ||
| if [ "$ACT_EXIT" != "$EXPECTED" ]; then | ||
| echo "::error::Fixture '${{ matrix.fixture }}': expected exit $EXPECTED but got $ACT_EXIT" | ||
| exit 1 | ||
| fi | ||
| echo "Fixture '${{ matrix.fixture }}': exit $ACT_EXIT — PASS" | ||
|
|
||
| # tests/common/release.yml and tests/common/release-preview.yml are validated | ||
| # by actionlint above. act-based execution is skipped here because act does not | ||
| # propagate with: inputs into nested workflow_call, and release-preview requires | ||
| # curl which is absent from the micro image. Both workflows are exercised | ||
| # end-to-end in the per-repo migration PRs. | ||
Check warningCode scanning / CodeQL Workflow does not contain permissions Medium
Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
|
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| name: Check Release | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| version-format: | ||
| description: "Version format to validate: semver | pep440 | maven" | ||
| required: true | ||
| type: string | ||
|
|
||
| jobs: | ||
| check-release: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Check ref is a tag | ||
| run: | | ||
| case "${{ github.ref }}" in | ||
| refs/tags/*) ;; | ||
| *) echo "::error::Expected a tag ref (refs/tags/...) but got: ${{ github.ref }}"; exit 1 ;; | ||
| esac | ||
|
|
||
| - name: Validate tag format (${{ inputs.version-format }}) | ||
| run: | | ||
| TAG="${{ github.ref_name }}" | ||
| FORMAT="${{ inputs.version-format }}" | ||
|
|
||
| case "$FORMAT" in | ||
| semver) | ||
| if ! npx --yes semver "$TAG" > /dev/null 2>&1; then | ||
| echo "::error::Tag '$TAG' is not valid npm semver (expected X.Y.Z or X.Y.Z-pre.N, no v prefix)" | ||
| exit 1 | ||
| fi | ||
| ;; | ||
| pep440) | ||
| if ! echo "$TAG" | grep -qE '^[0-9]+(\.[0-9]+)*(a[0-9]+|b[0-9]+|rc[0-9]+)?(\.post[0-9]+)?(\.dev[0-9]+)?$'; then | ||
| echo "::error::Tag '$TAG' is not a valid PEP 440 version (e.g. 1.2.3, 1.2.3rc1, 1.2.3.post1 — no v prefix)" | ||
| exit 1 | ||
| fi | ||
| ;; | ||
| maven) | ||
| if ! echo "$TAG" | grep -qE '^[0-9]+(\.[0-9]+)*(-[A-Za-z0-9._-]+)?$'; then | ||
| echo "::error::Tag '$TAG' is not a valid Maven version (e.g. 1.2.3, 1.2.3-RELEASE — no v prefix)" | ||
| exit 1 | ||
| fi | ||
| ;; | ||
| *) | ||
| echo "::error::Unknown version-format '$FORMAT'. Must be semver, pep440, or maven." | ||
| exit 1 | ||
| ;; | ||
| esac | ||
|
|
||
| - name: Check release branch | ||
| run: | | ||
| BRANCH="${{ github.event.release.target_commitish }}" | ||
| if [[ "$BRANCH" != "main" && "$BRANCH" != hotfix/* && "$BRANCH" != release/* ]]; then | ||
| echo "::error::Release must target main, hotfix/*, or release/* (got: '$BRANCH')" | ||
| exit 1 | ||
| fi |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| name: Publish to Docker Registry | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| version: | ||
| description: "Semver version to tag (no v prefix, e.g. 1.2.3)" | ||
| required: true | ||
| type: string | ||
| image-name: | ||
| description: "Image name without registry prefix (e.g. reqstool-org/reqstool)" | ||
| required: true | ||
| type: string | ||
| registry: | ||
| description: "Container registry hostname" | ||
| required: false | ||
| type: string | ||
| default: "ghcr.io" | ||
| dry-run: | ||
| description: "Build the image but do NOT push. No registry login required." | ||
| required: false | ||
| type: boolean | ||
| default: false | ||
|
|
||
| jobs: | ||
| publish: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| id-token: write | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Docker metadata | ||
| id: meta | ||
| uses: docker/metadata-action@v5 | ||
| with: | ||
| images: ${{ inputs.registry }}/${{ inputs.image-name }} | ||
| tags: | | ||
| type=semver,pattern={{version}},value=${{ inputs.version }} | ||
| type=semver,pattern={{major}}.{{minor}},value=${{ inputs.version }} | ||
| type=semver,pattern={{major}},value=${{ inputs.version }},enable=${{ !startsWith(inputs.version, '0.') }} | ||
| type=sha | ||
| type=raw,value=latest | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| - name: Log in to registry | ||
| if: ${{ !inputs.dry-run }} | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| registry: ${{ inputs.registry }} | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Build and push | ||
| uses: docker/build-push-action@v6 | ||
| with: | ||
| push: ${{ !inputs.dry-run }} | ||
| tags: ${{ steps.meta.outputs.tags }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
| build-args: VERSION=${{ inputs.version }} |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| name: Publish to GitHub Pages | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| node-version: | ||
| description: "Node.js version to use for Antora." | ||
| required: false | ||
| type: string | ||
| default: "24" | ||
| antora-playbook: | ||
| description: "Path to the Antora playbook file." | ||
| required: false | ||
| type: string | ||
| default: "docs/antora-playbook.yml" | ||
|
|
||
| concurrency: | ||
| group: github-pages | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| publish: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| pages: write | ||
| id-token: write | ||
| environment: | ||
| name: github-pages | ||
| url: ${{ steps.deployment.outputs.page_url }} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: actions/configure-pages@v5 | ||
|
|
||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: ${{ inputs.node-version }} | ||
|
|
||
| - name: Install Antora | ||
| run: npm i antora asciidoctor asciidoctor-kroki | ||
|
|
||
| - name: Build site | ||
| run: npx antora ${{ inputs.antora-playbook }} | ||
|
|
||
| - uses: actions/upload-pages-artifact@v3 | ||
| with: | ||
| path: docs/build/site | ||
|
|
||
| - name: Deploy to GitHub Pages | ||
| id: deployment | ||
| uses: actions/deploy-pages@v4 |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.