# -------------------------------------------------------------------- # docmd : the minimalist, zero-config documentation generator. # # @package @docmd/core (and ecosystem) # @website https://docmd.io # @repository https://github.com/docmd-io/docmd # @license MIT # @copyright Copyright (c) 2025-present docmd.io # # [docmd-source] - Please do not remove this header. # -------------------------------------------------------------------- # # GitHub Actions workflow for building and publishing Docker images # Uses OIDC (OpenID Connect) for passwordless authentication to GHCR # # Triggers: # - Release published on GitHub # - Manual workflow dispatch # - Push to main (for testing) # # -------------------------------------------------------------------- name: Build and Push Docker Image on: release: types: [published] push: tags: - 'v*' workflow_dispatch: inputs: push_image: description: 'Push image to registry' required: false default: true type: boolean version: description: 'Version tag (e.g., X.Y.Z)' required: false type: string tag_latest: description: 'Also tag this build as :latest (use only for stable releases)' required: false default: false type: boolean permissions: contents: read packages: write id-token: write # Required for OIDC env: REGISTRY: ghcr.io jobs: # --------------------------------------------------------------------------- # Build and push Docker image # --------------------------------------------------------------------------- build: name: Build Docker Image runs-on: ubuntu-latest outputs: version: ${{ steps.meta.outputs.version }} tags: ${{ steps.meta.outputs.tags }} steps: - name: Checkout repository uses: actions/checkout@v7 # ------------------------------------------------------------------------- # Set up Docker Buildx for multi-platform builds # ------------------------------------------------------------------------- - name: Set up QEMU uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 # ------------------------------------------------------------------------- # Login to GitHub Container Registry using OIDC # The id-token: write permission enables passwordless authentication # ------------------------------------------------------------------------- - name: Login to GitHub Container Registry uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # ------------------------------------------------------------------------- # Extract metadata for Docker # ------------------------------------------------------------------------- - name: Extract Docker metadata # Skip on plain branch pushes (the "for testing" trigger) — the # build below is local-only (push: is gated to release / manual), # so no tags are needed and the action's tag rules don't apply. if: github.event_name != 'push' || startsWith(github.ref, 'refs/tags/') id: meta uses: docker/metadata-action@v6 with: images: ${{ env.REGISTRY }}/${{ github.repository }} # Two and only two tags are ever produced for any single image: # - The version (e.g. X.Y.Z, v-prefix stripped) # - The floating `:latest` alias # `:latest` is only ever applied to released versions. A branch # build or unreleased commit can never be pulled as `:latest`. # flavor=latest=false disables the action's auto-latest so the # only source of `:latest` is the explicit rule below. flavor: | latest=false tags: | # Version: ref on tag push and release events (strips 'v' prefix) type=ref,event=tag # :latest — only on release events type=raw,value=latest,enable=${{ github.event_name == 'release' }} # Manual dispatch: use provided version + optional :latest type=raw,value=${{ inputs.version }},enable=${{ github.event_name == 'workflow_dispatch' && inputs.version != '' }} type=raw,value=latest,enable=${{ github.event_name == 'workflow_dispatch' && inputs.tag_latest }} labels: | org.opencontainers.image.title=docmd org.opencontainers.image.description=The minimalist, zero-config documentation generator org.opencontainers.image.vendor=docmd.io org.opencontainers.image.licenses=MIT # ------------------------------------------------------------------------- # Build and push Docker image # Multi-platform: linux/amd64, linux/arm64 # ------------------------------------------------------------------------- - name: Build and push Docker image uses: docker/build-push-action@v7 with: context: . file: ./docker/Dockerfile platforms: linux/amd64,linux/arm64 push: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.push_image) }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max provenance: true sbom: true # ------------------------------------------------------------------------- # Output build info # ------------------------------------------------------------------------- - name: Output image info run: | echo "## Docker Image Published! :whale:" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Image Details" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY echo "| Registry | \`${{ env.REGISTRY }}\` |" >> $GITHUB_STEP_SUMMARY echo "| Image | \`${{ env.REGISTRY }}/${{ github.repository }}:${{ steps.meta.outputs.version }}\` |" >> $GITHUB_STEP_SUMMARY echo "| Version | \`${{ steps.meta.outputs.version }}\` |" >> $GITHUB_STEP_SUMMARY echo "| Platforms | \`linux/amd64, linux/arm64\` |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Usage" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '```bash' >> $GITHUB_STEP_SUMMARY echo "# Pull the image" >> $GITHUB_STEP_SUMMARY echo "docker pull ${{ env.REGISTRY }}/${{ github.repository }}:${{ steps.meta.outputs.version }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "# Run development server" >> $GITHUB_STEP_SUMMARY echo "docker run -v \$(pwd)/docs:/docs -p 3000:3000 ${{ env.REGISTRY }}/${{ github.repository }}:${{ steps.meta.outputs.version }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "# Build static site" >> $GITHUB_STEP_SUMMARY echo "docker run -v \$(pwd)/docs:/docs -v \$(pwd)/site:/site ${{ env.REGISTRY }}/${{ github.repository }}:${{ steps.meta.outputs.version }} build" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY # --------------------------------------------------------------------------- # Test the Docker image (optional but recommended) # --------------------------------------------------------------------------- test: name: Test Docker Image needs: build runs-on: ubuntu-latest if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.push_image) steps: - name: Checkout repository uses: actions/checkout@v7 - name: Login to GitHub Container Registry uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Pull image run: docker pull ${{ env.REGISTRY }}/${{ github.repository }}:${{ needs.build.outputs.version }} - name: Test build command run: | # Create test directory with proper permissions for container user (UID 1001) mkdir -p /tmp/docmd-test sudo chown -R 1001:1001 /tmp/docmd-test # Simulate exactly what a new user does: init a project then build it docker run --rm \ -v /tmp/docmd-test:/workspace \ --workdir /workspace \ --entrypoint sh \ ${{ env.REGISTRY }}/${{ github.repository }}:${{ needs.build.outputs.version }} \ -c "cp -r /template/. /workspace/ && docmd build" - name: Verify build output run: | if [ -f "/tmp/docmd-test/site/index.html" ]; then echo "✅ Build successful - site/index.html exists" echo "📊 Site size: $(du -sh /tmp/docmd-test/site | cut -f1)" else echo "❌ Build failed - site/index.html not found" ls -la /tmp/docmd-test/ exit 1 fi