Merge pull request #3 from techquestsdev/dependabot/github_actions/do… #15
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 | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| packages: write | |
| id-token: write | |
| security-events: write | |
| attestations: write | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/') }} | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| jobs: | |
| semantic-version: | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'push' | |
| outputs: | |
| new_tag: ${{ steps.tag.outputs.new_tag }} | |
| changelog: ${{ steps.tag.outputs.changelog }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get latest tag | |
| id: get_tag | |
| run: | | |
| # Get the latest tag, or default to v0.0.0 | |
| LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") | |
| echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT | |
| echo "Latest tag: $LATEST_TAG" | |
| - name: Determine version bump | |
| id: bump | |
| run: | | |
| # Get the commit message | |
| COMMIT_MSG=$(git log -1 --pretty=%B) | |
| echo "Commit message: $COMMIT_MSG" | |
| # Determine bump type based on conventional commits | |
| if echo "$COMMIT_MSG" | grep -qiE '^(feat|fix|perf|refactor|style|test|docs|chore)!:' || echo "$COMMIT_MSG" | grep -qi 'BREAKING CHANGE'; then | |
| BUMP_TYPE="major" | |
| elif echo "$COMMIT_MSG" | grep -qiE '^feat(\(.+\))?:'; then | |
| BUMP_TYPE="minor" | |
| elif echo "$COMMIT_MSG" | grep -qiE '^(fix|perf)(\(.+\))?:'; then | |
| BUMP_TYPE="patch" | |
| else | |
| BUMP_TYPE="none" | |
| fi | |
| echo "bump_type=$BUMP_TYPE" >> $GITHUB_OUTPUT | |
| echo "Bump type: $BUMP_TYPE" | |
| - name: Calculate new version | |
| id: tag | |
| run: | | |
| # Only version on main branch pushes | |
| if [ "${GITHUB_REF}" != "refs/heads/main" ]; then | |
| echo "Not on main; skipping versioning" | |
| echo "new_tag=" >> $GITHUB_OUTPUT | |
| echo "changelog=" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| LATEST_TAG="${{ steps.get_tag.outputs.latest_tag }}" | |
| BUMP_TYPE="${{ steps.bump.outputs.bump_type }}" | |
| if [ "$BUMP_TYPE" = "none" ]; then | |
| echo "No semantic commit detected, skipping versioning" | |
| echo "new_tag=" >> $GITHUB_OUTPUT | |
| echo "changelog=" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # Remove 'v' prefix and split version | |
| VERSION=${LATEST_TAG#v} | |
| IFS='.' read -r -a VERSION_PARTS <<< "$VERSION" | |
| MAJOR=${VERSION_PARTS[0]:-0} | |
| MINOR=${VERSION_PARTS[1]:-0} | |
| PATCH=${VERSION_PARTS[2]:-0} | |
| # Bump version based on type | |
| case $BUMP_TYPE in | |
| major) | |
| MAJOR=$((MAJOR + 1)) | |
| MINOR=0 | |
| PATCH=0 | |
| ;; | |
| minor) | |
| MINOR=$((MINOR + 1)) | |
| PATCH=0 | |
| ;; | |
| patch) | |
| PATCH=$((PATCH + 1)) | |
| ;; | |
| esac | |
| NEW_TAG="v${MAJOR}.${MINOR}.${PATCH}" | |
| echo "new_tag=$NEW_TAG" >> $GITHUB_OUTPUT | |
| echo "New tag: $NEW_TAG" | |
| # Get commit message for changelog | |
| COMMIT_MSG=$(git log -1 --pretty=%B) | |
| { | |
| echo "changelog<<CHANGELOG_EOF" | |
| echo "$COMMIT_MSG" | |
| echo "CHANGELOG_EOF" | |
| } >> $GITHUB_OUTPUT | |
| - name: Create and push tag | |
| if: steps.tag.outputs.new_tag != '' | |
| run: | | |
| NEW_TAG="${{ steps.tag.outputs.new_tag }}" | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git tag -a "$NEW_TAG" -m "Release $NEW_TAG" | |
| git push origin "$NEW_TAG" | |
| echo "✓ Created and pushed tag: $NEW_TAG" | |
| build-and-push: | |
| runs-on: ubuntu-latest | |
| needs: [semantic-version] | |
| if: github.event_name != 'pull_request' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=ref,event=branch | |
| type=semver,pattern={{version}} | |
| type=sha,prefix={{branch}}-,enable={{is_default_branch}} | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| type=raw,value=${{ needs.semantic-version.outputs.new_tag }},enable=${{ needs.semantic-version.outputs.new_tag != '' }} | |
| - name: Build and push Docker image | |
| id: build | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| provenance: true | |
| sbom: true | |
| - name: Generate artifact attestation | |
| uses: actions/attest-build-provenance@v4 | |
| with: | |
| subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| subject-digest: ${{ steps.build.outputs.digest }} | |
| push-to-registry: true | |
| - name: Run Trivy vulnerability scanner (SARIF) | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} | |
| format: "sarif" | |
| output: "trivy-results.sarif" | |
| severity: "CRITICAL,HIGH" | |
| - name: Upload Trivy results to GitHub Security | |
| uses: github/codeql-action/upload-sarif@v4 | |
| if: always() | |
| with: | |
| sarif_file: "trivy-results.sarif" | |
| - name: Run Trivy vulnerability scanner (table) | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} | |
| format: "table" | |
| severity: "CRITICAL,HIGH" | |
| validate-docker: | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Build Docker image (validation only) | |
| id: build | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| push: false | |
| load: true | |
| tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:pr-${{ github.event.pull_request.number }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| - name: Run Trivy vulnerability scanner on PR | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:pr-${{ github.event.pull_request.number }} | |
| format: "table" | |
| severity: "CRITICAL,HIGH" | |
| exit-code: "1" | |
| create-release: | |
| runs-on: ubuntu-latest | |
| needs: [semantic-version, build-and-push] | |
| if: | | |
| github.event_name == 'push' && | |
| github.ref == 'refs/heads/main' && | |
| needs.semantic-version.outputs.new_tag != '' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.semantic-version.outputs.new_tag }} | |
| name: Release ${{ needs.semantic-version.outputs.new_tag }} | |
| body: | | |
| ## Changes | |
| ${{ needs.semantic-version.outputs.changelog }} | |
| ## Docker Image | |
| ```bash | |
| docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.semantic-version.outputs.new_tag }} | |
| ``` | |
| ## What's Changed | |
| **Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ needs.semantic-version.outputs.new_tag }}...main | |
| draft: false | |
| prerelease: false | |
| generate_release_notes: true |