CI/CD #421
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: CI/CD | |
| on: | |
| push: | |
| branches: [ '**' ] # this triggers only on branch commits, which prevents triggering off of tag-only commits | |
| paths-ignore: | |
| - .github/workflows/examples.yml | |
| - .github/workflows/move-tags.yml | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.ref }} | |
| jobs: | |
| version: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| elixir-version: ${{ steps.parse.outputs.elixir-version }} | |
| otp-version: ${{ steps.parse.outputs.otp-version }} | |
| previous-release-tag: ${{ steps.parse.outputs.previous-release-tag }} | |
| releasable: ${{ steps.parse.outputs.releasable }} | |
| semver: ${{ steps.parse.outputs.semver }} | |
| tag-exists: ${{ steps.parse.outputs.tag-exists }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: pkgxdev/dev@fix-erlang | |
| - name: Parse version | |
| id: parse | |
| uses: ./.github/actions/version | |
| with: | |
| semver: ${{ env.VERSION }} | |
| - name: Show outputs | |
| run: echo -e "Outputs:\n${{ toJSON(steps.parse.outputs) }}" | |
| test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: pkgxdev/dev@fix-erlang | |
| - run: mix deps.get | |
| - run: mix deps.compile | |
| - run: mix test | |
| audit: | |
| needs: [ version ] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: pkgxdev/dev@fix-erlang | |
| - run: mix deps.get | |
| - run: mix deps.compile | |
| - uses: ./.github/actions/dialyzer-cache | |
| with: | |
| otp-version: ${{ needs.version.outputs.otp-version }} | |
| elixir-version: ${{ needs.version.outputs.elixir-version }} | |
| - run: bin/audit --skip-check-image | |
| build: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: ./.github/actions/build-tar-image | |
| with: | |
| build-file: .github/Dockerfile | |
| build-context: . | |
| vulnerability-scanner: | |
| needs: [ build ] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: ./.github/actions/load-tar-image | |
| - name: Run Trivy vulnerability scanner | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| exit-code: '1' | |
| format: 'sarif' | |
| ignore-unfixed: true | |
| image-ref: ${{ env.IMAGE_NAME }} | |
| output: 'trivy-results.sarif' | |
| severity: 'MEDIUM,HIGH,CRITICAL' | |
| vuln-type: library | |
| - name: Upload Trivy scan results to GitHub Security tab | |
| uses: github/codeql-action/upload-sarif@v2 | |
| if: always() | |
| with: | |
| sarif_file: 'trivy-results.sarif' | |
| e2e-tests-discovery: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: pkgxdev/dev@fix-erlang | |
| - name: Resolve ERL_BASE | |
| run: | | |
| unset ERL_ROOTDIR | |
| ERL_BIN="$(command -v erl)" | |
| ERL_BIN_REAL="$(readlink -f "$ERL_BIN")" | |
| ERL_DIR="$(dirname "$(dirname "$ERL_BIN_REAL")")" | |
| if [ -d "$ERL_DIR/lib/erlang" ]; then | |
| ERL_BASE="$ERL_DIR/lib/erlang" | |
| else | |
| ERL_BASE="$ERL_DIR" | |
| fi | |
| echo "ERL_BASE=$ERL_BASE" >> "$GITHUB_ENV" | |
| echo "ERL_ROOTDIR=$ERL_BASE" >> "$GITHUB_ENV" | |
| - run: pkgx +invisible-island.net/ncurses -- mix deps.get | |
| - run: pkgx +invisible-island.net/ncurses -- mix deps.compile | |
| - id: set-matrix | |
| name: Discover E2E tests | |
| run: pkgx +invisible-island.net/ncurses -- mix e2e.set_github_matrix matrix | |
| e2e-tests: | |
| needs: [ build, e2e-tests-discovery ] | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{fromJson(needs.e2e-tests-discovery.outputs.matrix)}} | |
| runs-on: ubuntu-latest | |
| name: "e2e tests (${{ matrix.name }})" | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: ./.github/actions/load-tar-image | |
| - uses: ./.github/actions/run-e2e | |
| with: | |
| image-name: ${{ env.IMAGE_NAME }} | |
| script: ${{ matrix.script }} | |
| expected: ${{ matrix.expected }} | |
| env: | |
| GH_TOKEN: ${{ secrets.PAT }} | |
| push: | |
| needs: [ version, test, audit, build, e2e-tests, vulnerability-scanner ] | |
| runs-on: ubuntu-latest | |
| name: ${{ needs.version.outputs.releasable == 'true' && 'push' || 'push (dry-run)' }} | |
| permissions: | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: docker/setup-buildx-action@v3 | |
| - uses: ./.github/actions/load-tar-image | |
| - uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ github.token }} | |
| - uses: ./.github/actions/push-tar-image | |
| with: | |
| source-image: ${{ env.IMAGE_NAME }} | |
| semver: ${{ needs.version.outputs.semver }} | |
| exists: ${{ needs.version.outputs.tag-exists }} | |
| push: ${{ needs.version.outputs.releasable }} | |
| release: | |
| needs: [ version, push ] | |
| runs-on: ubuntu-latest | |
| name: ${{ needs.version.outputs.releasable == 'true' && 'release' || 'release (dry-run)' }} | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Generate release description | |
| run: | | |
| log_content() { | |
| local content="$1" | |
| local label="${2:-}" | |
| if [[ -n "$label" ]]; then | |
| # Replace the beginning of each line with two spaces | |
| local indented_content="${content//$'\n'/$'\n' }" | |
| printf "%s:\n %s\n" "$label" "$indented_content" | |
| else | |
| echo "$content" | |
| fi | |
| } | |
| CHANGELOG_URL="https://github.com/${{ github.event.repository.full_name }}/compare/${{ needs.version.outputs.previous-release-tag }}...v${{ needs.version.outputs.semver }}" | |
| echo "BODY=**Full Changelog**: $CHANGELOG_URL" >> $GITHUB_ENV | |
| echo ::group::Set outputs | |
| log_content "$(cat "$GITHUB_ENV")" "GITHUB_ENV" | |
| echo ::endgroup:: | |
| - uses: softprops/action-gh-release@v2 | |
| if: needs.version.outputs.releasable == 'true' | |
| with: | |
| body: ${{ env.BODY }} | |
| generate_release_notes: false | |
| tag_name: v${{ needs.version.outputs.semver }} | |
| token: ${{ secrets.PAT }} # using our own PAT so other workflows run |