Build and Push Docker Image #10
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
| # .github/workflows/docker-build.yml | |
| name: Build and Push Docker Image | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| release: | |
| types: [published] | |
| workflow_dispatch: | |
| inputs: | |
| tag_override: | |
| description: 'Override tag (optional)' | |
| required: false | |
| type: string | |
| force_build: | |
| description: 'Force build even if repository is private' | |
| required: false | |
| type: boolean | |
| default: false | |
| build_strategy: | |
| description: 'Build strategy' | |
| required: false | |
| type: choice | |
| default: 'buildx-multi' | |
| options: | |
| - 'buildx-multi' | |
| - 'buildx-single' | |
| - 'legacy' | |
| env: | |
| REGISTRY: ghcr.io | |
| jobs: | |
| check-repository-visibility: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| is_public: ${{ steps.check.outputs.is_public }} | |
| should_build: ${{ steps.check.outputs.should_build }} | |
| steps: | |
| - name: Check if repository is public | |
| id: check | |
| run: | | |
| REPO_INFO=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
| "https://api.github.com/repos/${{ github.repository }}") | |
| IS_PRIVATE=$(echo "$REPO_INFO" | jq -r '.private') | |
| if [ "$IS_PRIVATE" = "false" ]; then | |
| echo "is_public=true" >> $GITHUB_OUTPUT | |
| echo "should_build=true" >> $GITHUB_OUTPUT | |
| echo "Repository is public - proceeding with Docker build" | |
| elif [ "${{ github.event.inputs.force_build }}" = "true" ]; then | |
| echo "is_public=false" >> $GITHUB_OUTPUT | |
| echo "should_build=true" >> $GITHUB_OUTPUT | |
| echo "Repository is private but force_build is enabled - proceeding with Docker build" | |
| else | |
| echo "is_public=false" >> $GITHUB_OUTPUT | |
| echo "should_build=false" >> $GITHUB_OUTPUT | |
| echo "Repository is private - skipping Docker build" | |
| fi | |
| build-and-push: | |
| needs: check-repository-visibility | |
| if: needs.check-repository-visibility.outputs.should_build == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Convert repository name to lowercase | |
| id: repo | |
| run: echo "name=${GITHUB_REPOSITORY,,}" >> $GITHUB_OUTPUT | |
| - name: Set up QEMU (for multi-platform builds) | |
| if: github.event.inputs.build_strategy != 'legacy' | |
| uses: docker/setup-qemu-action@v3 | |
| with: | |
| platforms: linux/amd64,linux/arm64 | |
| - name: Set up Docker Buildx | |
| if: github.event.inputs.build_strategy != 'legacy' | |
| uses: docker/setup-buildx-action@v3 | |
| with: | |
| driver-opts: | | |
| network=host | |
| buildkitd-flags: | | |
| --allow-insecure-entitlement security.insecure | |
| --allow-insecure-entitlement network.host | |
| - 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@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ steps.repo.outputs.name }} | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=pr | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=semver,pattern={{major}} | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| labels: | | |
| org.opencontainers.image.title=Changerawr | |
| org.opencontainers.image.description=Ship, Change, Rawr 🦖 - Changelog management made cute and simple | |
| org.opencontainers.image.vendor=Supernova3339 | |
| org.opencontainers.image.url=https://github.com/${{ github.repository }} | |
| org.opencontainers.image.source=https://github.com/${{ github.repository }} | |
| org.opencontainers.image.documentation=https://github.com/${{ github.repository }}#readme | |
| - name: Determine final tags and build args | |
| id: build_config | |
| run: | | |
| if [ -n "${{ github.event.inputs.tag_override }}" ]; then | |
| echo "tags=${{ env.REGISTRY }}/${{ steps.repo.outputs.name }}:${{ github.event.inputs.tag_override }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "tags=${{ steps.meta.outputs.tags }}" >> $GITHUB_OUTPUT | |
| fi | |
| # Set build args | |
| echo "buildtime=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}" >> $GITHUB_OUTPUT | |
| echo "version=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}" >> $GITHUB_OUTPUT | |
| echo "revision=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }}" >> $GITHUB_OUTPUT | |
| # Strategy 1: Multi-platform buildx (default) | |
| - name: Build and push Docker image (Multi-platform) | |
| if: github.event.inputs.build_strategy == 'buildx-multi' || github.event.inputs.build_strategy == '' | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: ./Dockerfile | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: ${{ steps.build_config.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| build-args: | | |
| BUILDTIME=${{ steps.build_config.outputs.buildtime }} | |
| VERSION=${{ steps.build_config.outputs.version }} | |
| REVISION=${{ steps.build_config.outputs.revision }} | |
| provenance: false | |
| sbom: false | |
| # Strategy 2: Single platform buildx (fallback) | |
| - name: Build and push Docker image (Single platform) | |
| if: github.event.inputs.build_strategy == 'buildx-single' | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: ./Dockerfile | |
| platforms: linux/amd64 | |
| push: true | |
| tags: ${{ steps.build_config.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| build-args: | | |
| BUILDTIME=${{ steps.build_config.outputs.buildtime }} | |
| VERSION=${{ steps.build_config.outputs.version }} | |
| REVISION=${{ steps.build_config.outputs.revision }} | |
| provenance: false | |
| sbom: false | |
| # Strategy 3: Legacy docker build (last resort) | |
| - name: Build Docker image (Legacy) | |
| if: github.event.inputs.build_strategy == 'legacy' | |
| run: | | |
| # Get the first tag for legacy build | |
| FIRST_TAG=$(echo "${{ steps.build_config.outputs.tags }}" | head -n1) | |
| docker build \ | |
| --build-arg BUILDTIME="${{ steps.build_config.outputs.buildtime }}" \ | |
| --build-arg VERSION="${{ steps.build_config.outputs.version }}" \ | |
| --build-arg REVISION="${{ steps.build_config.outputs.revision }}" \ | |
| --tag "$FIRST_TAG" \ | |
| --file ./Dockerfile \ | |
| . | |
| - name: Push Docker image (Legacy) | |
| if: github.event.inputs.build_strategy == 'legacy' | |
| run: | | |
| # Push all tags for legacy build | |
| echo "${{ steps.build_config.outputs.tags }}" | while IFS= read -r tag; do | |
| if [ -n "$tag" ]; then | |
| echo "Pushing $tag" | |
| docker push "$tag" | |
| fi | |
| done | |
| - name: Generate image summary | |
| run: | | |
| echo "## Docker Image Built Successfully! 🦖" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ "${{ needs.check-repository-visibility.outputs.is_public }}" = "false" ]; then | |
| echo "⚠️ **Note:** Build was forced for private repository" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| BUILD_STRATEGY="${{ github.event.inputs.build_strategy }}" | |
| if [ -z "$BUILD_STRATEGY" ]; then | |
| BUILD_STRATEGY="buildx-multi" | |
| fi | |
| echo "**Build Strategy:** $BUILD_STRATEGY" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Image:** \`${{ env.REGISTRY }}/${{ steps.repo.outputs.name }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Tags:**" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| echo "${{ steps.build_config.outputs.tags }}" | tr ',' '\n' >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ "$BUILD_STRATEGY" = "legacy" ]; then | |
| echo "**Platforms:** linux/amd64" >> $GITHUB_STEP_SUMMARY | |
| elif [ "$BUILD_STRATEGY" = "buildx-single" ]; then | |
| echo "**Platforms:** linux/amd64" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "**Platforms:** linux/amd64, linux/arm64" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Pull Command:**" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY | |
| echo "docker pull ${{ env.REGISTRY }}/${{ steps.repo.outputs.name }}:latest" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| skip-build: | |
| needs: check-repository-visibility | |
| if: needs.check-repository-visibility.outputs.should_build == 'false' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Skip build notification | |
| run: | | |
| echo "## Build Skipped 🔒" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Docker image build was skipped because this repository is private." >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**To enable Docker builds:**" >> $GITHUB_STEP_SUMMARY | |
| echo "1. Make the repository public, or" >> $GITHUB_STEP_SUMMARY | |
| echo "2. Run workflow manually with 'Force build' option enabled, or" >> $GITHUB_STEP_SUMMARY | |
| echo "3. Modify the workflow to allow private builds by default" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Repository:** \`${{ github.repository }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "**Trigger:** \`${{ github.event_name }}\`" >> $GITHUB_STEP_SUMMARY |