diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index da81dce..26bc57d 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -9,41 +9,108 @@ jobs: publish: runs-on: ubuntu-latest permissions: - contents: read + contents: write packages: write steps: - - name: Checkout + - name: Checkout tag uses: actions/checkout@v4 + - name: Validate release tag + run: | + if [[ ! "${GITHUB_REF_NAME}" =~ ^v[0-9]+[.][0-9]+[.][0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then + echo "Release tags must use semver like v1.2.3 or v1.2.3-rc.1" + exit 1 + fi + - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Log in to Docker Hub + - name: Log in to GHCR uses: docker/login-action@v3 with: - username: ${{ secrets.DOCKER_HUB_USER }} - password: ${{ secrets.DOCKER_HUB_PAT }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} - name: Set image tag run: | - IMAGE_TAG="kuberhealthy/http-check:${GITHUB_REF_NAME}" - echo "IMAGE_TAG=${IMAGE_TAG}" >> $GITHUB_ENV + IMAGE_REPO="ghcr.io/kuberhealthy/http-check" + IMAGE_TAG="${IMAGE_REPO}:${GITHUB_REF_NAME}" + PACKAGE_URL="https://github.com/orgs/kuberhealthy/packages/container/package/http-check" + echo "IMAGE_REPO=${IMAGE_REPO}" >> "$GITHUB_ENV" + echo "IMAGE_TAG=${IMAGE_TAG}" >> "$GITHUB_ENV" + echo "PACKAGE_URL=${PACKAGE_URL}" >> "$GITHUB_ENV" - name: Build and push uses: docker/build-push-action@v6 with: context: . file: ./Containerfile + platforms: linux/amd64,linux/arm64 push: true tags: ${{ env.IMAGE_TAG }} + + - name: Update healthcheck examples + env: + GH_TOKEN: ${{ github.token }} + run: | + git fetch origin main + git checkout main + git pull --ff-only origin main + ruby -e 'image_tag = ENV.fetch("IMAGE_TAG"); files = Dir.glob("*.yaml") + Dir.glob("*.yml"); files.each do |path| text = File.read(path); updated = text.gsub(/(image:\s+)(?:\S*\/)?http\-check:[^\s]+/) { "#{$1}#{image_tag}" }; File.write(path, updated) if updated != text; end' + + if git diff --quiet; then + echo "No healthcheck image references needed updates." + exit 0 + fi + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add '*.yaml' '*.yml' + git commit -m "chore: update healthcheck image for ${GITHUB_REF_NAME}" + git push origin main + + - name: Create release notes + run: | + cat > release-images.txt < release-notes.md </dev/null 2>&1; then + gh release edit "${GITHUB_REF_NAME}" --title "${GITHUB_REF_NAME}" --notes-file release-notes.md + else + gh release create "${GITHUB_REF_NAME}" --title "${GITHUB_REF_NAME}" --notes-file release-notes.md --verify-tag + fi + gh release upload "${GITHUB_REF_NAME}" release-images.txt --clobber + - name: Publish summary run: | - TAG="${IMAGE_TAG#*:}" - IMAGE_REPO="${IMAGE_TAG%:*}" - IMAGE_URL="https://hub.docker.com/r/${IMAGE_REPO}/tags?name=${TAG}" - echo "Images pushed:" >> "$GITHUB_STEP_SUMMARY" + echo "Release created:" >> "$GITHUB_STEP_SUMMARY" + echo "- ${GITHUB_REF_NAME}" >> "$GITHUB_STEP_SUMMARY" + echo "Image pushed:" >> "$GITHUB_STEP_SUMMARY" echo "- ${IMAGE_TAG}" >> "$GITHUB_STEP_SUMMARY" - echo "- ${IMAGE_URL}" >> "$GITHUB_STEP_SUMMARY" + echo "Package:" >> "$GITHUB_STEP_SUMMARY" + echo "- ${PACKAGE_URL}" >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index bbecd99..4a4715d 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -21,30 +21,40 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Log in to Docker Hub + - name: Log in to GHCR uses: docker/login-action@v3 with: - username: ${{ secrets.DOCKER_HUB_USER }} - password: ${{ secrets.DOCKER_HUB_PAT }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} - name: Set image tag run: | SHORT_SHA=$(git rev-parse --short HEAD) - IMAGE_TAG="kuberhealthy/http-check:${SHORT_SHA}" - echo "IMAGE_TAG=${IMAGE_TAG}" >> $GITHUB_ENV + IMAGE_REPO="ghcr.io/kuberhealthy/http-check" + IMAGE_TAG="${IMAGE_REPO}:${SHORT_SHA}" + LATEST_IMAGE_TAG="${IMAGE_REPO}:latest" + PACKAGE_URL="https://github.com/orgs/kuberhealthy/packages/container/package/http-check" + echo "IMAGE_REPO=${IMAGE_REPO}" >> "$GITHUB_ENV" + echo "IMAGE_TAG=${IMAGE_TAG}" >> "$GITHUB_ENV" + echo "LATEST_IMAGE_TAG=${LATEST_IMAGE_TAG}" >> "$GITHUB_ENV" + echo "PACKAGE_URL=${PACKAGE_URL}" >> "$GITHUB_ENV" - name: Build and push uses: docker/build-push-action@v6 with: context: . file: ./Containerfile + platforms: linux/amd64,linux/arm64 push: true - tags: ${{ env.IMAGE_TAG }} + tags: | + ${{ env.IMAGE_TAG }} + ${{ env.LATEST_IMAGE_TAG }} + - name: Publish summary run: | - TAG="${IMAGE_TAG#*:}" - IMAGE_REPO="${IMAGE_TAG%:*}" - IMAGE_URL="https://hub.docker.com/r/${IMAGE_REPO}/tags?name=${TAG}" echo "Images pushed:" >> "$GITHUB_STEP_SUMMARY" echo "- ${IMAGE_TAG}" >> "$GITHUB_STEP_SUMMARY" - echo "- ${IMAGE_URL}" >> "$GITHUB_STEP_SUMMARY" + echo "- ${LATEST_IMAGE_TAG}" >> "$GITHUB_STEP_SUMMARY" + echo "Package:" >> "$GITHUB_STEP_SUMMARY" + echo "- ${PACKAGE_URL}" >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/validate-image-build.yaml b/.github/workflows/validate-image-build.yaml new file mode 100644 index 0000000..140954b --- /dev/null +++ b/.github/workflows/validate-image-build.yaml @@ -0,0 +1,37 @@ +name: Validate image build + +on: + pull_request: + branches: + - main + paths: + - "Containerfile" + - "go.mod" + - "go.sum" + - "cmd/**" + - ".github/workflows/validate-image-build.yaml" + - ".github/workflows/publish-tag.yaml" + - ".github/workflows/publish.yaml" + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Containerfile + platforms: linux/amd64,linux/arm64 + push: false diff --git a/Containerfile b/Containerfile index 83dad5a..e3ebae2 100644 --- a/Containerfile +++ b/Containerfile @@ -1,4 +1,6 @@ -FROM golang:1.24 AS builder +FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.24 AS builder +ARG TARGETOS +ARG TARGETARCH WORKDIR /build # Cache module downloads. @@ -8,7 +10,7 @@ RUN go mod download # Copy source and build. COPY . /build ENV CGO_ENABLED=0 -RUN go build -v -o /build/bin/http-check ./cmd/http-check +RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -v -o /build/bin/http-check ./cmd/http-check # Create a non-root user. RUN groupadd -g 999 user && \ diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..6af4204 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,29 @@ +# Release + +Releases are automated from semver git tags. + +To make a release, create and push a semver tag from the commit you want to release: + +```sh +git tag v1.2.3 +git push origin v1.2.3 +``` + +The `Publish tag` GitHub Actions workflow runs on `v*` tags and validates the tag format before publishing. Use `vMAJOR.MINOR.PATCH`, such as `v1.2.3`, or a prerelease tag like `v1.2.3-rc.1`. + +The workflow publishes this multi-arch image to GitHub Container Registry: + +```text +ghcr.io/kuberhealthy/http-check: +``` + +The image manifest includes: + +- `linux/amd64` +- `linux/arm64` + +After the image is pushed, the workflow updates the example healthcheck YAML on `main` to use the released GHCR image tag. + +The workflow then creates or updates a GitHub release with the same semver as the tag. The release notes link to the GitHub package, and the release includes a `release-images.txt` asset listing the image and supported platforms. + +Docker image tags do not support `+`, so do not use semver build metadata in release tags.