diff --git a/.github/workflows/publish-docker.yaml b/.github/workflows/publish-docker.yaml index ba10b71356..17da4c62bc 100644 --- a/.github/workflows/publish-docker.yaml +++ b/.github/workflows/publish-docker.yaml @@ -24,19 +24,33 @@ name: publish-docker # tagged x.y.z-, pushed to Docker Hub as # apache/skywalking-java-agent. # -# The release trigger is `released` rather than `published`, so publishing a -# pre-release does not ship official images. Creating the GitHub Release is the -# last step of `tools/releasing/release.sh vote-passed`. +# Releases publish by dispatch, deliberately, rather than by a `release` trigger. +# For a `release` event GitHub runs the workflow as it exists **at the tag**, and +# the tag is cut at `prepare` while the GitHub Release is published at +# `vote-passed`, at least 72 hours later. Anything changed here in between would +# silently not apply to the release in flight - that window is how 9.7.0 shipped +# with no workflow run at all. A dispatch always runs the workflow from the +# default branch, so what is on main is what publishes. +# +# `release.sh github-release` creates the Release and then dispatches this +# workflow, so this stays automatic; running it by hand from the Actions tab is +# how you retry a release whose images failed to push. on: push: branches: - main - release: - types: - - released + workflow_dispatch: + inputs: + version: + description: 'Release version to publish to Docker Hub, e.g. 9.7.0. Leave blank to build a development image from main.' + required: false + default: '' env: SKIP_TEST: true + # Non-empty exactly when this run publishes an official release. Everything + # below keys off this rather than the event name. + RELEASE_TAG: ${{ github.event.inputs.version }} jobs: # One agent package feeds every image. The variants differ only in the JRE they @@ -56,19 +70,19 @@ jobs: # Development images are compiled from the branch. - name: Cache local Maven repository - if: github.event_name != 'release' + if: env.RELEASE_TAG == '' uses: actions/cache@v4 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-publish-docker-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-maven-publish-docker- - uses: actions/setup-java@v2 - if: github.event_name != 'release' + if: env.RELEASE_TAG == '' with: distribution: temurin java-version: 17 - name: Build Agent - if: github.event_name != 'release' + if: env.RELEASE_TAG == '' run: make build # A release is never rebuilt. The published image has to carry the artifact @@ -79,11 +93,10 @@ jobs: # from dist/dev to dist/release immediately before the GitHub Release that # triggers this workflow, so the file is in place by the time this runs. - name: Download the released agent package - if: github.event_name == 'release' + if: env.RELEASE_TAG != '' run: | set -euo pipefail - TAG=${{ github.event.release.tag_name }} - VERSION=${TAG#v} + VERSION=${RELEASE_TAG#v} BASE="https://dist.apache.org/repos/dist/release/skywalking/java-agent/${VERSION}" TARBALL="apache-skywalking-java-agent-${VERSION}.tgz" @@ -120,18 +133,32 @@ jobs: # A release publishes the complete set the previous manual `make # docker.push.*` produced, alpine included. Per-commit development # images keep the existing JRE-only set. - base: ${{ github.event_name == 'release' && fromJSON('["alpine","java8","java11","java17","java21","java25"]') || fromJSON('["java8","java11","java17","java21","java25"]') }} + base: ${{ github.event.inputs.version && fromJSON('["alpine","java8","java11","java17","java21","java25"]') || fromJSON('["java8","java11","java17","java21","java25"]') }} steps: - uses: actions/checkout@v2 with: submodules: true + # The workflow file necessarily comes from the default branch on a + # dispatch - that is the point, it is what makes the run deterministic. The + # tree it builds must not. Dockerfile and Makefile decide what the image + # actually is, so for a release take them from the tag, exactly as the + # release:perform build and the source tarball did. + - name: Check out the released tag + if: env.RELEASE_TAG != '' + run: | + set -euo pipefail + VERSION=${RELEASE_TAG#v} + git fetch --depth 1 origin "refs/tags/v${VERSION}:refs/tags/v${VERSION}" + git checkout "refs/tags/v${VERSION}" + git submodule update --init --depth 1 + git --no-pager log -1 --format='building from %h %d' - uses: actions/download-artifact@v4 with: name: skywalking-agent path: skywalking-agent - name: Set environment variables run: | - if [[ "${{ github.event_name }}" == "release" ]]; then + if [[ -n "${RELEASE_TAG}" ]]; then # Provisioned by ASF INFRA on request, as for apache/skywalking. # Without them docker/login-action fails with an opaque error, so say # what is actually missing. @@ -149,8 +176,7 @@ jobs: echo "DOCKER_REGISTRY=docker.io" >> $GITHUB_ENV echo "DOCKER_USERNAME=${{ secrets.DOCKERHUB_USER }}" >> $GITHUB_ENV echo "DOCKER_PASSWORD=${{ secrets.DOCKERHUB_TOKEN }}" >> $GITHUB_ENV - TAG=${{ github.event.release.tag_name }} - echo "TAG=${TAG#v}" >> $GITHUB_ENV + echo "TAG=${RELEASE_TAG#v}" >> $GITHUB_ENV else echo "HUB=ghcr.io/apache/skywalking-java" >> $GITHUB_ENV echo "DOCKER_REGISTRY=ghcr.io" >> $GITHUB_ENV diff --git a/docs/en/contribution/release-java-agent.md b/docs/en/contribution/release-java-agent.md index 71b8c500b4..541f01379f 100644 --- a/docs/en/contribution/release-java-agent.md +++ b/docs/en/contribution/release-java-agent.md @@ -134,14 +134,29 @@ After the vote passes, run `vote-passed` which executes: 4. **cleanup** (optional) — if old version is provided, remove it from `dist/release`. Update download page links to point to `https://archive.apache.org/dist/skywalking` ### Docker images -Docker images are published by GitHub Actions, not from your machine. Publishing the -GitHub Release fires the `release: released` trigger in -[`.github/workflows/publish-docker.yaml`](../../../.github/workflows/publish-docker.yaml), -which builds every base variant and pushes +Docker images are published by GitHub Actions, not from your machine. `github-release` +publishes the GitHub Release and then dispatches +[`.github/workflows/publish-docker.yaml`](../../../.github/workflows/publish-docker.yaml) +with the release version. It builds every base variant and pushes `apache/skywalking-java-agent:x.y.z-{alpine,java8,java11,java17,java21,java25}` to Docker -Hub for `linux/amd64` and `linux/arm64`. Watch that workflow; if it fails you can fall back -to pushing from your machine with `./tools/releasing/release.sh docker x.y.z`, which needs -you to be logged in to Docker Hub with push access to the `apache` organisation. +Hub for `linux/amd64` and `linux/arm64`. Watch that workflow. + +If it fails, run it again: **Actions → publish-docker → Run workflow**, entering the +version (`9.7.0`). That is the same path `github-release` takes, so retrying is safe and +idempotent. + +> [!NOTE] +> There is deliberately **no `release:` trigger**. GitHub runs a release event's workflow as +> it exists *at the tag*, and the tag is cut at `prepare` while the Release is published at +> `vote-passed`, at least 72 hours later — so any change to the workflow in between would +> silently not apply to the release in flight. That window is why 9.7.0 published with no +> workflow run at all. Dispatching instead means the workflow always comes from `main`, +> while everything it acts on comes from the tag: the tree it builds is checked out at +> `vx.y.z`, and the agent package is the verified tarball from `dist/release`. + +As a last resort you can push from your machine with +`./tools/releasing/release.sh docker x.y.z`, which needs you to be logged in to Docker Hub +with push access to the `apache` organisation. The image contains the exact tarball that was voted on. The workflow downloads `apache-skywalking-java-agent-x.y.z.tgz` from `dist/release`, checks it against the diff --git a/tools/releasing/release.sh b/tools/releasing/release.sh index 210bd56a12..72e06e7aa8 100755 --- a/tools/releasing/release.sh +++ b/tools/releasing/release.sh @@ -689,11 +689,26 @@ cmd_github_release() { fi gh release create "${tag}" --title "${version}" "${notes_args[@]}" - info "GitHub Release ${tag} published." - info " publish-docker.yaml is now pushing to Docker Hub:" - info " apache/skywalking-java-agent:${version}-{alpine,java8,java11,java17,java21,java25}" - info " Watch: https://github.com/apache/skywalking-java/actions/workflows/publish-docker.yaml" + + # Dispatch rather than let a `release` trigger fire. GitHub runs a release + # event's workflow as it exists at the tag, and the tag is cut at `prepare` + # while this runs at `vote-passed`, at least 72 hours later - anything + # changed in publish-docker.yaml in between would silently not apply. A + # dispatch always runs the workflow from the default branch, so the release + # publishes with what is on main, and builds from the tag. + info "Dispatching publish-docker for ${version}..." + if gh workflow run publish-docker.yaml -f version="${version}"; then + info " Pushing to Docker Hub:" + info " apache/skywalking-java-agent:${version}-{alpine,java8,java11,java17,java21,java25}" + info " Watch: https://github.com/apache/skywalking-java/actions/workflows/publish-docker.yaml" + else + warn " Could not dispatch publish-docker. The release itself is published;" + warn " only the images are missing. Retry with:" + warn " gh workflow run publish-docker.yaml -f version=${version}" + warn " or from Actions -> publish-docker -> Run workflow, or as a last resort" + warn " $0 docker ${version}" + fi } # ============================================================