name: Build and Push Docker Images on: push: branches: [main] paths: - 'backend/**' - 'frontend/**' - 'docker-compose*.yml' - '.github/workflows/docker-build.yml' tags: ['v*'] workflow_dispatch: inputs: tag: description: 'Image tag (leave empty for "latest")' required: false default: '' # Default minimal permissions permissions: contents: read env: REGISTRY: ghcr.io jobs: # ============================================================================= # Build and Push Docker Images # Tests are NOT run here — branch protection on main requires all PR checks # (backend-test + frontend-build from test.yml) to pass before merge. # Tags are created from main, so code is already tested. # # Tag builds (v*) always set "latest" in addition to the semver tags. # This ensures "latest" always points to the most recent release. # ============================================================================= build-and-push: runs-on: ubuntu-latest permissions: contents: read packages: write strategy: matrix: include: - context: ./backend image: backend - context: ./frontend image: frontend steps: - name: Checkout repository uses: actions/checkout@v4 - 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@v5 with: images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/medassist-ng-${{ matrix.image }} tags: | type=ref,event=branch type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=raw,value=${{ github.event.inputs.tag || 'latest' }},enable=${{ github.event_name == 'workflow_dispatch' }} type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') }} - name: Build and push uses: docker/build-push-action@v5 with: context: ${{ matrix.context }} push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max platforms: linux/amd64,linux/arm64 provenance: false sbom: false # ============================================================================= # Create GitHub Release (only on tag push) # ============================================================================= create-release: runs-on: ubuntu-latest needs: build-and-push if: startsWith(github.ref, 'refs/tags/v') permissions: contents: write steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 # Fetch all history for changelog generation - name: Check if release exists id: check_release run: | CURRENT_TAG=${GITHUB_REF#refs/tags/} if gh release view "$CURRENT_TAG" &>/dev/null; then echo "exists=true" >> $GITHUB_OUTPUT echo "Release $CURRENT_TAG already exists, skipping creation" else echo "exists=false" >> $GITHUB_OUTPUT fi env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Get previous tag if: steps.check_release.outputs.exists == 'false' id: prev_tag run: | PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") echo "tag=${PREV_TAG}" >> $GITHUB_OUTPUT - name: Generate changelog if: steps.check_release.outputs.exists == 'false' id: changelog run: | CURRENT_TAG=${GITHUB_REF#refs/tags/} PREV_TAG="${{ steps.prev_tag.outputs.tag }}" echo "## What's Changed" > changelog.md echo "" >> changelog.md if [ -n "$PREV_TAG" ]; then # Get commits between tags git log ${PREV_TAG}..${CURRENT_TAG} --pretty=format:"* %s (%h)" --no-merges >> changelog.md else # First release - get recent commits git log -20 --pretty=format:"* %s (%h)" --no-merges >> changelog.md fi echo "" >> changelog.md echo "" >> changelog.md echo "## Docker Images" >> changelog.md echo "" >> changelog.md echo '```bash' >> changelog.md echo "docker pull ghcr.io/${{ github.repository_owner }}/medassist-ng-backend:${CURRENT_TAG#v}" >> changelog.md echo "docker pull ghcr.io/${{ github.repository_owner }}/medassist-ng-frontend:${CURRENT_TAG#v}" >> changelog.md echo '```' >> changelog.md echo "" >> changelog.md echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREV_TAG}...${CURRENT_TAG}" >> changelog.md - name: Create GitHub Release if: steps.check_release.outputs.exists == 'false' uses: softprops/action-gh-release@v2 with: body_path: changelog.md generate_release_notes: false draft: false prerelease: ${{ contains(github.ref, '-rc') || contains(github.ref, '-beta') || contains(github.ref, '-alpha') }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}