diff --git a/.github/workflows/build-and-publish-docker.yml b/.github/workflows/build-and-publish-docker.yml new file mode 100644 index 000000000..00bd416d8 --- /dev/null +++ b/.github/workflows/build-and-publish-docker.yml @@ -0,0 +1,123 @@ +name: Build and Publish Docker Image + +on: + workflow_dispatch: + inputs: + version: + description: 'Version tag for the Docker image (e.g., 1.2.3 or v1.2.3)' + required: true + type: string + publish: + description: 'Push the image to Docker Hub' + required: false + type: boolean + default: true + tag_latest: + description: 'Also tag this image as latest' + required: false + type: boolean + default: false + +permissions: + contents: read + +jobs: + build-and-publish: + name: Build and Publish Docker Image + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Get build metadata from release + id: meta + env: + INPUT_VERSION: ${{ inputs.version }} + INPUT_TAG_LATEST: ${{ inputs.tag_latest }} + uses: actions/github-script@v8 + with: + script: | + const inputVersion = process.env.INPUT_VERSION; + const inputTagLatest = process.env.INPUT_TAG_LATEST; + + const version = inputVersion.startsWith('v') ? inputVersion.slice(1) : inputVersion; + const releaseTag = inputVersion.startsWith('v') ? inputVersion : `v${inputVersion}`; + + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: context.repo.owner, + repo: context.repo.repo, + tag: releaseTag + }); + + const cliSha = release.target_commitish; + const imageShaTag = cliSha.substring(0, 7); + + core.setOutput('cli_sha', cliSha); + core.setOutput('image_sha_tag', imageShaTag); + core.setOutput('version', version); + core.setOutput('release_tag', releaseTag); + core.setOutput('tag_latest', inputTagLatest === 'true'); + + - name: Download release assets + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ steps.meta.outputs.release_tag }} + run: | + echo "Downloading assets from release ${RELEASE_TAG}..." + gh release download "${RELEASE_TAG}" --pattern "temporal_*_linux_*.tar.gz" + + echo "Extracting and organizing binaries..." + mkdir -p dist/amd64 dist/arm64 + + tar -xzf temporal_*_linux_amd64.tar.gz + mv temporal dist/amd64/temporal + + tar -xzf temporal_*_linux_arm64.tar.gz + mv temporal dist/arm64/temporal + + echo "Verifying binaries..." + ls -lh dist/amd64/temporal + ls -lh dist/arm64/temporal + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + if: inputs.publish + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push Docker image + if: inputs.publish + run: | + docker buildx bake \ + --file docker-bake.hcl \ + --push \ + cli + env: + CLI_SHA: ${{ steps.meta.outputs.cli_sha }} + IMAGE_SHA_TAG: ${{ steps.meta.outputs.image_sha_tag }} + VERSION: ${{ steps.meta.outputs.version }} + TAG_LATEST: ${{ steps.meta.outputs.tag_latest }} + IMAGE_NAMESPACE: temporalio + IMAGE_NAME: temporal + GITHUB_REPOSITORY: ${{ github.repository }} + + - name: Build Docker image (no push) + if: ${{ !inputs.publish }} + run: | + docker buildx bake \ + --file docker-bake.hcl \ + cli + env: + CLI_SHA: ${{ steps.meta.outputs.cli_sha }} + IMAGE_SHA_TAG: ${{ steps.meta.outputs.image_sha_tag }} + VERSION: ${{ steps.meta.outputs.version }} + TAG_LATEST: ${{ steps.meta.outputs.tag_latest }} + IMAGE_NAMESPACE: temporalio + IMAGE_NAME: temporal + GITHUB_REPOSITORY: ${{ github.repository }} diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/release.yml similarity index 58% rename from .github/workflows/goreleaser.yml rename to .github/workflows/release.yml index 3ef1d0b13..0bcd5d666 100644 --- a/.github/workflows/goreleaser.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: goreleaser +name: Release on: workflow_dispatch: @@ -6,45 +6,50 @@ on: types: - published +permissions: + contents: write + jobs: - goreleaser: + release: + name: Release runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + uses: actions/setup-go@v6 with: go-version-file: "go.mod" check-latest: true + cache: true - name: Get build date id: date - run: echo "::set-output name=date::$(date '+%F-%T')" + run: echo "date=$(date '+%F-%T')" >> "$GITHUB_OUTPUT" - name: Get build unix timestamp id: timestamp - run: echo "::set-output name=timestamp::$(date '+%s')" + run: echo "timestamp=$(date '+%s')" >> "$GITHUB_OUTPUT" - name: Get git branch id: branch - run: echo "::set-output name=branch::$(git rev-parse --abbrev-ref HEAD)" + run: echo "branch=$(git rev-parse --abbrev-ref HEAD)" >> "$GITHUB_OUTPUT" - name: Get build platform id: platform - run: echo "::set-output name=platform::$(go version | cut -d ' ' -f 4)" + run: echo "platform=$(go version | cut -d ' ' -f 4)" >> "$GITHUB_OUTPUT" - name: Get Go version id: go - run: echo "::set-output name=go::$(go version | cut -d ' ' -f 3)" + run: echo "go=$(go version | cut -d ' ' -f 3)" >> "$GITHUB_OUTPUT" - name: Run GoReleaser - uses: goreleaser/goreleaser-action@336e29918d653399e599bfca99fadc1d7ffbc9f7 # v4.3.0 + uses: goreleaser/goreleaser-action@v6 with: - version: v1.26.2 + version: v2.12.7 args: release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/trigger-docs.yml b/.github/workflows/trigger-docs.yml index 645d976b5..cfa6349a8 100644 --- a/.github/workflows/trigger-docs.yml +++ b/.github/workflows/trigger-docs.yml @@ -3,8 +3,13 @@ on: workflow_dispatch: release: types: [published] + +permissions: + contents: read + jobs: update: + if: github.repository == 'temporalio/cli' runs-on: ubuntu-latest defaults: run: @@ -12,23 +17,25 @@ jobs: steps: - name: Get user info from GitHub API id: get_user + env: + GITHUB_ACTOR: ${{ github.actor }} run: | - echo "GitHub actor: ${{ github.actor }}" + echo "GitHub actor: ${GITHUB_ACTOR}" # Query the GitHub API for the user's details. curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - https://api.github.com/users/${{ github.actor }} > user.json - + "https://api.github.com/users/${GITHUB_ACTOR}" > user.json + # Extract the user's full name if available, default to the username otherwise. git_name=$(jq -r '.name // empty' user.json) if [ -z "$git_name" ]; then - git_name="${{ github.actor }}" + git_name="${GITHUB_ACTOR}" fi - - git_email="${{ github.actor }}@users.noreply.github.com" - + + git_email="${GITHUB_ACTOR}@users.noreply.github.com" + # Set the outputs for subsequent steps. - echo "GIT_NAME=$git_name" >> $GITHUB_OUTPUT - echo "GIT_EMAIL=$git_email" >> $GITHUB_OUTPUT + echo "GIT_NAME=$git_name" >> "$GITHUB_OUTPUT" + echo "GIT_EMAIL=$git_email" >> "$GITHUB_OUTPUT" - name: Generate token id: generate_token diff --git a/.github/workflows/trigger-publish.yml b/.github/workflows/trigger-publish.yml deleted file mode 100644 index 6f65fefe4..000000000 --- a/.github/workflows/trigger-publish.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: 'Trigger Docker image build' - -on: - workflow_dispatch: - release: - types: [published] - -jobs: - trigger: - if: ${{ ! contains(github.ref, '-rc.') }} - name: 'trigger Docker image build' - runs-on: ubuntu-latest - - defaults: - run: - shell: bash - - steps: - - name: Generate a token - id: generate_token - uses: actions/create-github-app-token@v2 - with: - app-id: ${{ secrets.TEMPORAL_CICD_APP_ID }} - private-key: ${{ secrets.TEMPORAL_CICD_PRIVATE_KEY }} - owner: temporalio - repositories: | - cli - docker-builds - - - name: Dispatch docker builds Github Action - env: - PAT: ${{ steps.generate_token.outputs.token }} - PARENT_REPO: temporalio/docker-builds - PARENT_BRANCH: ${{ toJSON('main') }} - WORKFLOW_ID: update-submodules.yml - REPO: ${{ toJSON('cli') }} - BRANCH: ${{ toJSON('main') }} - COMMIT: ${{ toJSON(github.sha) }} - run: | - curl -fL -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token $PAT" "https://api.github.com/repos/$PARENT_REPO/actions/workflows/$WORKFLOW_ID/dispatches" -d '{"ref":'"$PARENT_BRANCH"', "inputs": { "repo":'"$REPO"', "branch":'"$BRANCH"', "commit": '"$COMMIT"' }}' diff --git a/.goreleaser.yml b/.goreleaser.yml index 9c94e1b4f..f3e29ced2 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,3 +1,5 @@ +version: 2 + before: hooks: - go mod download @@ -11,24 +13,26 @@ archives: - <<: &archive_defaults name_template: "temporal_cli_{{ .Version }}_{{ .Os }}_{{ .Arch }}" id: nix - builds: + ids: - nix - format: tar.gz + formats: + - tar.gz files: - LICENSE - <<: *archive_defaults id: windows-zip - builds: + ids: - windows - format: zip + formats: + - zip files: - LICENSE # used by SDKs as zip cannot be used by rust https://github.com/zip-rs/zip/issues/108 - <<: *archive_defaults id: windows-targz - builds: + ids: - windows files: - LICENSE @@ -61,7 +65,7 @@ checksum: algorithm: sha256 changelog: - skip: true + disable: true announce: skip: "true" diff --git a/Dockerfile b/Dockerfile index 05c3938a3..ca9d986f6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,9 @@ -FROM --platform=$BUILDARCH scratch AS dist -COPY ./dist/nix_linux_amd64_v1/temporal /dist/amd64/temporal -COPY ./dist/nix_linux_arm64/temporal /dist/arm64/temporal +FROM alpine:3.22@sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412 -FROM alpine:3.22 ARG TARGETARCH -RUN apk add --no-cache ca-certificates -COPY --from=dist /dist/$TARGETARCH/temporal /usr/local/bin/temporal + +RUN apk add --no-cache ca-certificates tzdata +COPY dist/${TARGETARCH}/temporal /usr/local/bin/temporal RUN adduser -u 1000 -D temporal USER temporal diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 000000000..66156cf2e --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,45 @@ +variable "IMAGE_NAMESPACE" { + default = "" +} + +variable "IMAGE_NAME" { + default = "temporal" +} + +variable "GITHUB_REPOSITORY" { + default = "temporalio/cli" +} + +variable "IMAGE_SHA_TAG" {} + +variable "CLI_SHA" { + default = "" +} + +variable "VERSION" { + default = "dev" +} + +variable "TAG_LATEST" { + default = false +} + +target "cli" { + dockerfile = "Dockerfile" + context = "." + tags = compact([ + "${IMAGE_NAMESPACE}/${IMAGE_NAME}:${IMAGE_SHA_TAG}", + "${IMAGE_NAMESPACE}/${IMAGE_NAME}:${VERSION}", + TAG_LATEST ? "${IMAGE_NAMESPACE}/${IMAGE_NAME}:latest" : "", + ]) + platforms = ["linux/amd64", "linux/arm64"] + labels = { + "org.opencontainers.image.title" = "temporal" + "org.opencontainers.image.description" = "Temporal CLI" + "org.opencontainers.image.url" = "https://github.com/${GITHUB_REPOSITORY}" + "org.opencontainers.image.source" = "https://github.com/${GITHUB_REPOSITORY}" + "org.opencontainers.image.licenses" = "MIT" + "org.opencontainers.image.revision" = "${CLI_SHA}" + "org.opencontainers.image.created" = timestamp() + } +}