name: Build and Push Docker Image on: push: branches: - master - main pull_request: branches: - master - main jobs: # Detects version changes in package.json compared to previous commit # Outputs the current version and whether it changed from the last commit # This is used to determine if a new release/build is needed check_version: runs-on: ubuntu-latest outputs: version_changed: ${{ steps.version-check.outputs.version_changed }} version: ${{ steps.version-check.outputs.version }} steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Check if version changed id: version-check run: | # Get current version CURRENT_VERSION=$(node -p "require('./package.json').version") echo "Current version: $CURRENT_VERSION" echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT # Check if HEAD~1 exists (handle first commit) if ! git rev-parse HEAD~1 &>/dev/null; then echo "First commit detected, running workflow" echo "version_changed=true" >> $GITHUB_OUTPUT exit 0 fi # Check if package.json exists in previous commit if ! git show HEAD~1:package.json &>/dev/null; then echo "package.json doesn't exist in previous commit" echo "version_changed=true" >> $GITHUB_OUTPUT exit 0 fi # Extract previous version using grep/sed (safer than node for old file) PREVIOUS_VERSION=$(git show HEAD~1:package.json | grep '"version"' | head -1 | sed -E 's/.*"version"\s*:\s*"([^"]+)".*/\1/') echo "Previous version: $PREVIOUS_VERSION" # Compare versions if [ "$CURRENT_VERSION" != "$PREVIOUS_VERSION" ]; then echo "Version changed: $PREVIOUS_VERSION -> $CURRENT_VERSION" echo "version_changed=true" >> $GITHUB_OUTPUT else echo "Version unchanged: $CURRENT_VERSION" echo "version_changed=false" >> $GITHUB_OUTPUT fi # Verifies if Docker image with current version already exists in registry # This prevents rebuilding the same version but allows pulls and version changes # to always trigger new builds. Uses lightweight manifest inspect (no download) check_image_version: runs-on: ubuntu-latest outputs: image_exists: ${{ steps.manifest-check.outputs.image_exists }} version: ${{ steps.version-read.outputs.version }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Read version from package.json id: version-read run: | VERSION=$(node -p "require('./package.json').version") echo "version=$VERSION" >> $GITHUB_OUTPUT echo "Checking for image version: $VERSION" - name: Login to Registry run: | echo "${{ secrets.PROFILE_REGISTRY_TOKEN }}" | docker login registry.budakova.org -u "${{ vars.PROFILE_REGISTRY_USERNAME }}" --password-stdin - name: Check if image exists in registry id: manifest-check run: | VERSION=${{ steps.version-read.outputs.version }} IMAGE="registry.budakova.org/knee-cola/gitea-actions-demo-project:${VERSION}" echo "Checking manifest for image: $IMAGE" if docker manifest inspect "$IMAGE" &>/dev/null; then echo "Image exists in registry" echo "image_exists=true" >> $GITHUB_OUTPUT else echo "Image does not exist in registry" echo "image_exists=false" >> $GITHUB_OUTPUT fi - name: Summary run: | echo "Version: ${{ steps.version-read.outputs.version }}" echo "Image exists: ${{ steps.manifest-check.outputs.image_exists }}" # Builds and pushes Docker image to registry if conditions are met: # - Version changed in package.json, OR # - Image with current version doesn't exist in registry, OR # - This is a pull request (always validate PRs) # This ensures releases are built, missing images are created, and PRs are tested build: needs: [check_version, check_image_version] if: | needs.check_version.outputs.version_changed == 'true' || needs.check_image_version.outputs.image_exists == 'false' || github.event_name == 'pull_request' runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Registry # Gitea automatically provides these secrets: # - `vars.REGISTRY_USERNAME` - defined as action variable in **repo settings** # - `secrets.REGISTRY_TOKEN` - defined as action secret in **repo settings** # created in user settings as personal access token with `write:packages` scope # - `vars.PROFILE_REGISTRY_USERNAME` - defined as action variable in **profile settings** # - `secrets.PROFILE_REGISTRY_TOKEN` - defined as action secret in **profile settings** # created in user settings as personal access token with `write:packages` scope run: | echo "${{ secrets.PROFILE_REGISTRY_TOKEN }}" | docker login registry.budakova.org -u "${{ vars.PROFILE_REGISTRY_USERNAME }}" --password-stdin - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . push: true tags: | registry.budakova.org/knee-cola/gitea-actions-demo-project:${{ needs.check_version.outputs.version }} registry.budakova.org/knee-cola/gitea-actions-demo-project:latest cache-from: type=registry,ref=registry.budakova.org/knee-cola/gitea-actions-demo-project:buildcache cache-to: type=registry,ref=registry.budakova.org/knee-cola/gitea-actions-demo-project:buildcache,mode=max