From 5d5f8819da9105b4365ed77fbdede0ca11437390 Mon Sep 17 00:00:00 2001 From: Aaron Zeisler Date: Thu, 7 May 2026 16:29:55 -0700 Subject: [PATCH 1/5] [SDK-2337] Replace GoReleaser with custom build scripts Remove the 529-line .goreleaser.yml and replace it with three focused shell scripts that handle cross-compilation, system packaging, and Docker image builds independently. - scripts/cross-compile.sh: builds all 9 OS/arch targets using go build, produces .tar.gz archives and checksums.txt - scripts/build-packages.sh: uses standalone nfpm to create .deb/.rpm packages from pre-built binaries - scripts/docker-build.sh: uses docker buildx for multi-platform builds across 3 image variants, creates multi-arch manifests - nfpm.yml: standalone package configuration (previously embedded in GoReleaser config) - Updated .github/actions/publish/action.yml to orchestrate the new scripts, preserving attestation outputs and dry-run support - Updated Dockerfiles to accept BINARY build arg for flexible binary path injection - Updated Makefile publish/products-for-release targets Tracked by SDK-2337. Co-authored-by: Cursor --- .github/actions/publish/action.yml | 56 +- .goreleaser.yml | 528 ------------------ ...e-static-debian12-debug-nonroot.goreleaser | 6 +- Dockerfile-static-debian12-nonroot.goreleaser | 6 +- Dockerfile.goreleaser | 6 +- Makefile | 7 +- nfpm.yml | 32 ++ scripts/build-packages.sh | 59 ++ scripts/cross-compile.sh | 83 +++ scripts/docker-build.sh | 226 ++++++++ scripts/run-goreleaser.sh | 16 - 11 files changed, 451 insertions(+), 574 deletions(-) delete mode 100644 .goreleaser.yml create mode 100644 nfpm.yml create mode 100755 scripts/build-packages.sh create mode 100755 scripts/cross-compile.sh create mode 100755 scripts/docker-build.sh delete mode 100755 scripts/run-goreleaser.sh diff --git a/.github/actions/publish/action.yml b/.github/actions/publish/action.yml index e54dc8ba..ba9ac6ac 100644 --- a/.github/actions/publish/action.yml +++ b/.github/actions/publish/action.yml @@ -21,7 +21,7 @@ inputs: default: 'false' outputs: checksum_file: - description: path to the sha256 checksums file generated by goreleaser + description: path to the sha256 checksums file value: ${{ steps.binary.outputs.checksum_file }} images_and_digests: description: built docker image names and digests in JSON format @@ -36,44 +36,56 @@ runs: uses: docker/setup-buildx-action@v3 with: platforms: linux/amd64,linux/arm64/v8,linux/arm/v7,linux/386 - - name: Git clean - shell: bash - run: git clean -f - name: Login to Docker + if: inputs.dry-run != 'true' shell: bash run: | echo $DOCKER_TOKEN | docker login --username $DOCKER_USERNAME --password-stdin - - name: Run Goreleaser - id: goreleaser - uses: goreleaser/goreleaser-action@v6 - with: - args: release --clean ${{ inputs.dry-run == 'true' && '--skip=publish' || '' }} + + - name: Extract version from tag + id: version + shell: bash + run: | + TAG="${{ inputs.tag }}" + VERSION="${TAG#v}" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + - name: Cross-compile binaries + shell: bash + run: | + ./scripts/cross-compile.sh --keep-build "${{ steps.version.outputs.version }}" + + - name: Build system packages + shell: bash + run: | + ./scripts/build-packages.sh "${{ steps.version.outputs.version }}" + + - name: Build and push Docker images + shell: bash env: - GITHUB_TOKEN: ${{ inputs.token }} LD_RELEASER_UPDATE_MAJOR: ${{ inputs.update-major-tag }} LD_RELEASER_UPDATE_LATEST: ${{ inputs.update-latest-tag }} - - name: Generate binary hashes + run: | + ./scripts/docker-build.sh ${{ inputs.dry-run == 'true' && '--dry-run' || '' }} "${{ steps.version.outputs.version }}" + + - name: Output checksum file path id: binary shell: bash - env: - ARTIFACTS: ${{ steps.goreleaser.outputs.artifacts }} run: | - # Extract path to checksums file generated by goreleaser - set -euo pipefail + echo "checksum_file=dist/checksums.txt" >> "$GITHUB_OUTPUT" - checksum_file=$(echo "$ARTIFACTS" | jq -r '.[] | select (.type=="Checksum") | .path') - echo "checksum_file=$checksum_file" >> "$GITHUB_OUTPUT" - name: Output image and digest id: image shell: bash - env: - ARTIFACTS: "${{ steps.goreleaser.outputs.artifacts }}" run: | - # Generate image digest - set -euo pipefail - echo "images_and_digests=$(echo "$ARTIFACTS" | jq -c '. | map(select (.type=="Docker Manifest") | .image=(.path | split(":")[0]) | .digest=(.extra | .Digest) | {image, digest})')" >> "$GITHUB_OUTPUT" + if [[ -f dist/images_and_digests.json ]]; then + echo "images_and_digests=$(cat dist/images_and_digests.json)" >> "$GITHUB_OUTPUT" + else + echo "images_and_digests=[]" >> "$GITHUB_OUTPUT" + fi - name: Upload Release Artifacts + if: inputs.dry-run != 'true' shell: bash env: GITHUB_TOKEN: ${{ inputs.token }} diff --git a/.goreleaser.yml b/.goreleaser.yml deleted file mode 100644 index 5dfae016..00000000 --- a/.goreleaser.yml +++ /dev/null @@ -1,528 +0,0 @@ -version: 2 - -project_name: ld-relay - -builds: -- env: - - CGO_ENABLED=0 - main: . - binary: ld-relay - # Default is `-s -w -X main.version={{.Version}} -X main.commit={{.ShortCommit}} -X main.date={{.Date}}`. - ldflags: - - -s -w -X internal.version.Version={{.Version}} - goos: - - darwin - - linux - - windows - goarch: - - '386' - - amd64 - - arm - - arm64 - goarm: - - "7" - ignore: # Go 1.15+ doesn't support 32-bit Darwin - - goos: darwin - goarch: '386' - - goos: windows - goarch: arm - -nfpms: - - - file_name_template: >- - {{ .ConventionalFileName }} - homepage: https://launchdarkly.com/ - maintainer: LaunchDarkly - description: LaunchDarkly Stream Relay Proxy - license: Apache 2.0 - vendor: Catamorphic Co. - - formats: - - deb - - rpm - - contents: - - src: linux/etc/ld-relay.conf - dst: /etc/ld-relay.conf - type: config - - - src: linux/etc/init/ld-relay.conf - dst: /etc/init/ld-relay.conf - packager: deb - - - src: linux/etc/system/ld-relay.service - dst: /usr/lib/systemd/system/ld-relay.service - packager: rpm - - - overrides: - deb: - dependencies: - - upstart - rpm: - dependencies: - - systemd - -release: - disable: true # this disables releasing *to GitHub*; it will still push to Docker - # (we want Releaser to be responsible for doing all the GitHub release manipulations) - -dockers: - # - # The following templates are for the Alpine-based image. - # - - # i386 - - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-i386" - use: buildx - goos: linux - goarch: "386" - dockerfile: Dockerfile.goreleaser - skip_push: false - build_flag_templates: - - "--pull" - - "--platform=linux/386" - - - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-i386" - use: buildx - goos: linux - goarch: "386" - dockerfile: Dockerfile.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/386" - - - image_templates: - - "launchdarkly/ld-relay:latest-i386" - use: buildx - goos: linux - goarch: "386" - dockerfile: Dockerfile.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/386" - - # AMD64 - - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-amd64" - use: buildx - goos: linux - goarch: amd64 - dockerfile: Dockerfile.goreleaser - skip_push: false - build_flag_templates: - - "--pull" - - "--platform=linux/amd64" - - - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-amd64" - use: buildx - goos: linux - goarch: amd64 - dockerfile: Dockerfile.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/amd64" - - - image_templates: - - "launchdarkly/ld-relay:latest-amd64" - use: buildx - goos: linux - goarch: amd64 - dockerfile: Dockerfile.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/amd64" - - # ARMv7 - - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-armv7" - use: buildx - goos: linux - goarch: arm - goarm: 7 - dockerfile: Dockerfile.goreleaser - skip_push: false - build_flag_templates: - - "--pull" - - "--platform=linux/arm/v7" - - - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-armv7" - use: buildx - goos: linux - goarch: arm - goarm: 7 - dockerfile: Dockerfile.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/arm/v7" - - - image_templates: - - "launchdarkly/ld-relay:latest-armv7" - use: buildx - goos: linux - goarch: arm - goarm: 7 - dockerfile: Dockerfile.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/arm/v7" - - # ARM64v8 - - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-arm64v8" - use: buildx - goos: linux - goarch: arm64 - dockerfile: Dockerfile.goreleaser - skip_push: false - build_flag_templates: - - "--pull" - - "--platform=linux/arm64/v8" - - - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-arm64v8" - use: buildx - goos: linux - goarch: arm64 - dockerfile: Dockerfile.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/arm64/v8" - - - image_templates: - - "launchdarkly/ld-relay:latest-arm64v8" - use: buildx - goos: linux - goarch: arm64 - dockerfile: Dockerfile.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/arm64/v8" - - # - # The following image templates are for the nonroot debian12 distroless image. - # - - # AMD64 - - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-static-debian12-nonroot-amd64" - use: buildx - goos: linux - goarch: amd64 - dockerfile: Dockerfile-static-debian12-nonroot.goreleaser - skip_push: false - build_flag_templates: - - "--pull" - - "--platform=linux/amd64" - - - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-nonroot-amd64" - use: buildx - goos: linux - goarch: amd64 - dockerfile: Dockerfile-static-debian12-nonroot.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/amd64" - - - image_templates: - - "launchdarkly/ld-relay:latest-static-debian12-nonroot-amd64" - use: buildx - goos: linux - goarch: amd64 - dockerfile: Dockerfile-static-debian12-nonroot.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/amd64" - - # ARMv7 - - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-static-debian12-nonroot-armv7" - use: buildx - goos: linux - goarch: arm - goarm: 7 - dockerfile: Dockerfile-static-debian12-nonroot.goreleaser - skip_push: false - build_flag_templates: - - "--pull" - - "--platform=linux/arm/v7" - - - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-nonroot-armv7" - use: buildx - goos: linux - goarch: arm - goarm: 7 - dockerfile: Dockerfile-static-debian12-nonroot.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/arm/v7" - - - image_templates: - - "launchdarkly/ld-relay:latest-static-debian12-nonroot-armv7" - use: buildx - goos: linux - goarch: arm - goarm: 7 - dockerfile: Dockerfile-static-debian12-nonroot.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/arm/v7" - - # ARM64v8 - - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-static-debian12-nonroot-arm64v8" - use: buildx - goos: linux - goarch: arm64 - dockerfile: Dockerfile-static-debian12-nonroot.goreleaser - skip_push: false - build_flag_templates: - - "--pull" - - "--platform=linux/arm64/v8" - - - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-nonroot-arm64v8" - use: buildx - goos: linux - goarch: arm64 - dockerfile: Dockerfile-static-debian12-nonroot.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/arm64/v8" - - - image_templates: - - "launchdarkly/ld-relay:latest-static-debian12-nonroot-arm64v8" - use: buildx - goos: linux - goarch: arm64 - dockerfile: Dockerfile-static-debian12-nonroot.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/arm64/v8" - - # - # The following image templates are for the debug nonroot debian12 distroless image. This image is - # necessary to get a shell in the container for debugging purposes. - # - - # AMD64 - - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-static-debian12-debug-nonroot-amd64" - use: buildx - goos: linux - goarch: amd64 - dockerfile: Dockerfile-static-debian12-debug-nonroot.goreleaser - skip_push: false - build_flag_templates: - - "--pull" - - "--platform=linux/amd64" - - - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-debug-nonroot-amd64" - use: buildx - goos: linux - goarch: amd64 - dockerfile: Dockerfile-static-debian12-debug-nonroot.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/amd64" - - - image_templates: - - "launchdarkly/ld-relay:latest-static-debian12-debug-nonroot-amd64" - use: buildx - goos: linux - goarch: amd64 - dockerfile: Dockerfile-static-debian12-debug-nonroot.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/amd64" - - # ARMv7 - - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-static-debian12-debug-nonroot-armv7" - use: buildx - goos: linux - goarch: arm - goarm: 7 - dockerfile: Dockerfile-static-debian12-debug-nonroot.goreleaser - skip_push: false - build_flag_templates: - - "--pull" - - "--platform=linux/arm/v7" - - - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-debug-nonroot-armv7" - use: buildx - goos: linux - goarch: arm - goarm: 7 - dockerfile: Dockerfile-static-debian12-debug-nonroot.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/arm/v7" - - - image_templates: - - "launchdarkly/ld-relay:latest-static-debian12-debug-nonroot-armv7" - use: buildx - goos: linux - goarch: arm - goarm: 7 - dockerfile: Dockerfile-static-debian12-debug-nonroot.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/arm/v7" - - # ARM64v8 - - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-static-debian12-debug-nonroot-arm64v8" - use: buildx - goos: linux - goarch: arm64 - dockerfile: Dockerfile-static-debian12-debug-nonroot.goreleaser - skip_push: false - build_flag_templates: - - "--pull" - - "--platform=linux/arm64/v8" - - - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-debug-nonroot-arm64v8" - use: buildx - goos: linux - goarch: arm64 - dockerfile: Dockerfile-static-debian12-debug-nonroot.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/arm64/v8" - - - image_templates: - - "launchdarkly/ld-relay:latest-static-debian12-debug-nonroot-arm64v8" - use: buildx - goos: linux - goarch: arm64 - dockerfile: Dockerfile-static-debian12-debug-nonroot.goreleaser - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - build_flag_templates: - - "--pull" - - "--platform=linux/arm64/v8" - -docker_manifests: - # For backwards compatibility, we publish the :latest, :vX, and :x.y.z tags for Alpine without any suffix - # indicating that the image is Alpine based (unlike the debian12 images). This is because it's what was done historically, - # and we cannot change it yet without breaking existing users. - - name_template: "launchdarkly/ld-relay:{{ .Version}}" - skip_push: false - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-amd64" - - "launchdarkly/ld-relay:{{ .Version }}-armv7" - - "launchdarkly/ld-relay:{{ .Version }}-arm64v8" - - "launchdarkly/ld-relay:{{ .Version }}-i386" - - - name_template: "launchdarkly/ld-relay:v{{ .Major }}" - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-amd64" - - "launchdarkly/ld-relay:v{{ .Major }}-armv7" - - "launchdarkly/ld-relay:v{{ .Major }}-arm64v8" - - "launchdarkly/ld-relay:v{{ .Major }}-i386" - - - name_template: "launchdarkly/ld-relay:latest" - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - image_templates: - - "launchdarkly/ld-relay:latest-amd64" - - "launchdarkly/ld-relay:latest-armv7" - - "launchdarkly/ld-relay:latest-arm64v8" - - "launchdarkly/ld-relay:latest-i386" - - # We'll also create aliases for the Alpine-based image with the suffix "-alpine" to make it easier to distinguish - # from the debian12 image. This will also allow us to eventually deprecate the non-suffixed tags in a future major version. - - name_template: "launchdarkly/ld-relay:{{ .Version}}-alpine" - skip_push: false - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-amd64" - - "launchdarkly/ld-relay:{{ .Version }}-armv7" - - "launchdarkly/ld-relay:{{ .Version }}-arm64v8" - - "launchdarkly/ld-relay:{{ .Version }}-i386" - - - name_template: "launchdarkly/ld-relay:v{{ .Major }}-alpine" - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-amd64" - - "launchdarkly/ld-relay:v{{ .Major }}-armv7" - - "launchdarkly/ld-relay:v{{ .Major }}-arm64v8" - - "launchdarkly/ld-relay:v{{ .Major }}-i386" - - - name_template: "launchdarkly/ld-relay:latest-alpine" - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - image_templates: - - "launchdarkly/ld-relay:latest-amd64" - - "launchdarkly/ld-relay:latest-armv7" - - "launchdarkly/ld-relay:latest-arm64v8" - - "launchdarkly/ld-relay:latest-i386" - - # For the static debian12 image - - name_template: "launchdarkly/ld-relay:{{ .Version}}-static-debian12-nonroot" - skip_push: false - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-static-debian12-nonroot-amd64" - - "launchdarkly/ld-relay:{{ .Version }}-static-debian12-nonroot-armv7" - - "launchdarkly/ld-relay:{{ .Version }}-static-debian12-nonroot-arm64v8" - - - name_template: "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-nonroot" - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-nonroot-amd64" - - "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-nonroot-armv7" - - "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-nonroot-arm64v8" - - - name_template: "launchdarkly/ld-relay:latest-static-debian12-nonroot" - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - image_templates: - - "launchdarkly/ld-relay:latest-static-debian12-nonroot-amd64" - - "launchdarkly/ld-relay:latest-static-debian12-nonroot-armv7" - - "launchdarkly/ld-relay:latest-static-debian12-nonroot-arm64v8" - # For the debug static debian12 image - - name_template: "launchdarkly/ld-relay:{{ .Version}}-static-debian12-debug-nonroot" - skip_push: false - image_templates: - - "launchdarkly/ld-relay:{{ .Version }}-static-debian12-debug-nonroot-amd64" - - "launchdarkly/ld-relay:{{ .Version }}-static-debian12-debug-nonroot-armv7" - - "launchdarkly/ld-relay:{{ .Version }}-static-debian12-debug-nonroot-arm64v8" - - - name_template: "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-debug-nonroot" - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_MAJOR "true" }}' - image_templates: - - "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-debug-nonroot-amd64" - - "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-debug-nonroot-armv7" - - "launchdarkly/ld-relay:v{{ .Major }}-static-debian12-debug-nonroot-arm64v8" - - - name_template: "launchdarkly/ld-relay:latest-static-debian12-debug-nonroot" - skip_push: '{{ ne .Env.LD_RELEASER_UPDATE_LATEST "true" }}' - image_templates: - - "launchdarkly/ld-relay:latest-static-debian12-debug-nonroot-amd64" - - "launchdarkly/ld-relay:latest-static-debian12-debug-nonroot-armv7" - - "launchdarkly/ld-relay:latest-static-debian12-debug-nonroot-arm64v8" diff --git a/Dockerfile-static-debian12-debug-nonroot.goreleaser b/Dockerfile-static-debian12-debug-nonroot.goreleaser index 426fce4e..d1c5cd60 100644 --- a/Dockerfile-static-debian12-debug-nonroot.goreleaser +++ b/Dockerfile-static-debian12-debug-nonroot.goreleaser @@ -1,9 +1,11 @@ -# This is a Dockerfile used for release (published to dockerhub by goreleaser) +# This is a Dockerfile used for release (published to dockerhub) FROM gcr.io/distroless/static-debian12:debug-nonroot # See "Runtime platform versions" in CONTRIBUTING.md -COPY ld-relay /usr/bin/ldr +ARG BINARY=ld-relay + +COPY ${BINARY} /usr/bin/ldr EXPOSE 8030 ENV PORT=8030 diff --git a/Dockerfile-static-debian12-nonroot.goreleaser b/Dockerfile-static-debian12-nonroot.goreleaser index 8291427e..c2328c9f 100644 --- a/Dockerfile-static-debian12-nonroot.goreleaser +++ b/Dockerfile-static-debian12-nonroot.goreleaser @@ -1,9 +1,11 @@ -# This is a Dockerfile used for release (published to dockerhub by goreleaser) +# This is a Dockerfile used for release (published to dockerhub) FROM gcr.io/distroless/static-debian12:nonroot # See "Runtime platform versions" in CONTRIBUTING.md -COPY ld-relay /usr/bin/ldr +ARG BINARY=ld-relay + +COPY ${BINARY} /usr/bin/ldr EXPOSE 8030 ENV PORT=8030 diff --git a/Dockerfile.goreleaser b/Dockerfile.goreleaser index 4da0fadf..5c3a7558 100644 --- a/Dockerfile.goreleaser +++ b/Dockerfile.goreleaser @@ -1,15 +1,17 @@ -# This is a Dockerfile used for release (published to dockerhub by goreleaser) +# This is a Dockerfile used for release (published to dockerhub) FROM alpine:3.23.4 # See "Runtime platform versions" in CONTRIBUTING.md +ARG BINARY=ld-relay + RUN apk add --no-cache \ ca-certificates \ && apk add --upgrade libcrypto3 libssl3 \ && update-ca-certificates \ && rm -rf /var/cache/apk/* -COPY ld-relay /usr/bin/ldr +COPY ${BINARY} /usr/bin/ldr RUN addgroup -g 1000 -S ldr-user && \ adduser -u 1000 -S ldr-user -G ldr-user && \ diff --git a/Makefile b/Makefile index 56a82cdd..a23f6105 100644 --- a/Makefile +++ b/Makefile @@ -60,10 +60,13 @@ echo-release-notes: @cat $(RELEASE_NOTES) publish: - ./scripts/run-goreleaser.sh + ./scripts/cross-compile.sh --keep-build + ./scripts/build-packages.sh + ./scripts/docker-build.sh products-for-release: - ./scripts/run-goreleaser.sh --skip=publish --skip=validate + ./scripts/cross-compile.sh --keep-build + ./scripts/build-packages.sh DOCKER_COMPOSE_TEST=docker-compose -f docker-compose.test.yml diff --git a/nfpm.yml b/nfpm.yml new file mode 100644 index 00000000..9522644c --- /dev/null +++ b/nfpm.yml @@ -0,0 +1,32 @@ +name: ld-relay +arch: "${NFPM_ARCH}" +version: "v${VERSION}" +homepage: https://launchdarkly.com/ +maintainer: LaunchDarkly +description: LaunchDarkly Stream Relay Proxy +license: Apache 2.0 +vendor: Catamorphic Co. + +contents: + - src: ./dist/build/ld-relay_${VERSION}_linux_${NFPM_ARCH_LABEL}/ld-relay + dst: /usr/bin/ld-relay + + - src: linux/etc/ld-relay.conf + dst: /etc/ld-relay.conf + type: config + + - src: linux/etc/init/ld-relay.conf + dst: /etc/init/ld-relay.conf + packager: deb + + - src: linux/etc/system/ld-relay.service + dst: /usr/lib/systemd/system/ld-relay.service + packager: rpm + +overrides: + deb: + dependencies: + - upstart + rpm: + dependencies: + - systemd diff --git a/scripts/build-packages.sh b/scripts/build-packages.sh new file mode 100755 index 00000000..5b3783a5 --- /dev/null +++ b/scripts/build-packages.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Build .deb and .rpm packages using nFPM. +# Requires: nfpm (https://nfpm.goreleaser.com/install/) +# Expects binaries to already exist in dist/build/ (run cross-compile.sh first with --keep-build). +# +# Usage: ./scripts/build-packages.sh [VERSION] + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +cd "$PROJECT_ROOT" + +VERSION="${1:-$(sed -n 's/.*Version = "\([^"]*\)".*/\1/p' relay/version/version.go)}" +DIST_DIR="$PROJECT_ROOT/dist" + +# Architectures to package (linux only) +# Format: nfpm_arch:cross_compile_label +ARCHS=( + "amd64:amd64" + "386:386" + "arm64:arm64" + "armhf:armv7" +) + +# Note: nfpm arch names differ from Go arch names in some cases: +# nfpm "armhf" = Go "arm" (v7) +# nfpm "386" = Go "386" + +echo "Building packages for ld-relay v${VERSION}..." + +# Ensure the linux binaries exist +for entry in "${ARCHS[@]}"; do + IFS=':' read -r nfpm_arch arch_label <<< "$entry" + binary="$DIST_DIR/build/ld-relay_${VERSION}_linux_${arch_label}/ld-relay" + if [[ ! -f "$binary" ]]; then + echo "Error: Binary not found at $binary" + echo "Run cross-compile.sh with --keep-build first, or rebuild the linux targets." + exit 1 + fi +done + +for entry in "${ARCHS[@]}"; do + IFS=':' read -r nfpm_arch arch_label <<< "$entry" + + for format in deb rpm; do + echo " ${format} (${arch_label})..." + NFPM_ARCH="$nfpm_arch" NFPM_ARCH_LABEL="$arch_label" VERSION="$VERSION" \ + nfpm package \ + --config "$PROJECT_ROOT/nfpm.yml" \ + --packager "$format" \ + --target "$DIST_DIR/" + done +done + +echo "" +echo "Done. Packages in $DIST_DIR:" +ls -lh "$DIST_DIR"/*.deb "$DIST_DIR"/*.rpm 2>/dev/null || echo " (none found)" diff --git a/scripts/cross-compile.sh b/scripts/cross-compile.sh new file mode 100755 index 00000000..1b78dcff --- /dev/null +++ b/scripts/cross-compile.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Cross-compile ld-relay for all supported OS/architecture targets. +# Produces tarballs and a checksums file in the dist/ directory. +# +# Usage: ./scripts/cross-compile.sh [--keep-build] [VERSION] +# --keep-build: Keep the intermediate build directory (needed for build-packages.sh) +# VERSION defaults to the value in relay/version/version.go + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +cd "$PROJECT_ROOT" + +KEEP_BUILD=false +if [[ "${1:-}" == "--keep-build" ]]; then + KEEP_BUILD=true + shift +fi + +VERSION="${1:-$(sed -n 's/.*Version = "\([^"]*\)".*/\1/p' relay/version/version.go)}" +DIST_DIR="$PROJECT_ROOT/dist" +LDFLAGS="-s -w" + +# OS/arch matrix (all supported targets; darwin/386 and windows/arm excluded) +TARGETS=( + "darwin/amd64" + "darwin/arm64" + "linux/386" + "linux/amd64" + "linux/arm/7" + "linux/arm64" + "windows/386" + "windows/amd64" + "windows/arm64" +) + +rm -rf "$DIST_DIR" +mkdir -p "$DIST_DIR" + +echo "Building ld-relay v${VERSION} for ${#TARGETS[@]} targets..." + +for target in "${TARGETS[@]}"; do + IFS='/' read -r goos goarch goarm <<< "$target" + + suffix="" + arch_label="$goarch" + if [[ "$goarch" == "arm" && -n "$goarm" ]]; then + arch_label="armv${goarm}" + fi + + binary_name="ld-relay" + if [[ "$goos" == "windows" ]]; then + binary_name="ld-relay.exe" + fi + + archive_name="ld-relay_${VERSION}_${goos}_${arch_label}" + build_dir="$DIST_DIR/build/${archive_name}" + mkdir -p "$build_dir" + + echo " ${goos}/${arch_label}..." + + GOARM="${goarm:-}" CGO_ENABLED=0 GOOS="$goos" GOARCH="$goarch" \ + go build -trimpath -ldflags "$LDFLAGS" -o "$build_dir/$binary_name" . + + cp README.md "$build_dir/" 2>/dev/null || true + cp LICENSE "$build_dir/" 2>/dev/null || true + + tar -C "$DIST_DIR/build" -czf "$DIST_DIR/${archive_name}.tar.gz" "$archive_name" +done + +echo "Generating checksums..." +cd "$DIST_DIR" +shasum -a 256 *.tar.gz > checksums.txt + +if [[ "$KEEP_BUILD" == "false" ]]; then + rm -rf "$DIST_DIR/build" +fi + +echo "" +echo "Done. Artifacts in $DIST_DIR:" +ls -lh "$DIST_DIR" diff --git a/scripts/docker-build.sh b/scripts/docker-build.sh new file mode 100755 index 00000000..76e03e39 --- /dev/null +++ b/scripts/docker-build.sh @@ -0,0 +1,226 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Build and push multi-arch Docker images for ld-relay. +# Produces images for 3 variants (alpine, distroless nonroot, distroless debug) across multiple architectures, +# then creates multi-arch manifests. +# +# Usage: ./scripts/docker-build.sh [--dry-run] [VERSION] +# +# Environment variables: +# LD_RELEASER_UPDATE_MAJOR - "true" to also tag as vMAJOR (e.g. v8) +# LD_RELEASER_UPDATE_LATEST - "true" to also tag as latest + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +cd "$PROJECT_ROOT" + +DRY_RUN=false +if [[ "${1:-}" == "--dry-run" ]]; then + DRY_RUN=true + shift +fi + +VERSION="${1:-$(sed -n 's/.*Version = "\([^"]*\)".*/\1/p' relay/version/version.go)}" +MAJOR_VERSION="${VERSION%%.*}" +IMAGE="launchdarkly/ld-relay" + +UPDATE_MAJOR="${LD_RELEASER_UPDATE_MAJOR:-false}" +UPDATE_LATEST="${LD_RELEASER_UPDATE_LATEST:-false}" + +DIST_DIR="$PROJECT_ROOT/dist" +LDFLAGS="-s -w" + +# Image variant definitions: name suffix, dockerfile, architectures +declare -A VARIANT_DOCKERFILES=( + ["alpine"]="Dockerfile.goreleaser" + ["static-debian12-nonroot"]="Dockerfile-static-debian12-nonroot.goreleaser" + ["static-debian12-debug-nonroot"]="Dockerfile-static-debian12-debug-nonroot.goreleaser" +) + +# Alpine supports all 4 archs; distroless only supports 3 (no i386) +declare -A VARIANT_PLATFORMS=( + ["alpine"]="linux/amd64,linux/arm64/v8,linux/arm/v7,linux/386" + ["static-debian12-nonroot"]="linux/amd64,linux/arm64/v8,linux/arm/v7" + ["static-debian12-debug-nonroot"]="linux/amd64,linux/arm64/v8,linux/arm/v7" +) + +# Architecture label mapping for Docker tags +declare -A ARCH_LABELS=( + ["linux/amd64"]="amd64" + ["linux/arm64/v8"]="arm64v8" + ["linux/arm/v7"]="armv7" + ["linux/386"]="i386" +) + +# Architecture label mapping for binary paths (matches cross-compile.sh output) +declare -A BINARY_ARCH_LABELS=( + ["linux/amd64"]="amd64" + ["linux/arm64/v8"]="arm64" + ["linux/arm/v7"]="armv7" + ["linux/386"]="386" +) + +PUSH_FLAG="" +if [[ "$DRY_RUN" == "false" ]]; then + PUSH_FLAG="--push" +fi + +# Collect manifest digests for attestation output +MANIFESTS_JSON="[]" + +push_or_load() { + if [[ "$DRY_RUN" == "true" ]]; then + echo " (dry-run: skipping push)" + fi +} + +build_variant() { + local variant="$1" + local dockerfile="${VARIANT_DOCKERFILES[$variant]}" + local platforms="${VARIANT_PLATFORMS[$variant]}" + + # Determine tag suffix (alpine has no suffix for backwards compatibility) + local tag_suffix="" + if [[ "$variant" != "alpine" ]]; then + tag_suffix="-${variant}" + fi + + echo "" + echo "=== Building variant: ${variant} ===" + echo " Dockerfile: ${dockerfile}" + echo " Platforms: ${platforms}" + + # Build per-architecture images for version tag + IFS=',' read -ra platform_list <<< "$platforms" + for platform in "${platform_list[@]}"; do + local arch_label="${ARCH_LABELS[$platform]}" + local tag="${IMAGE}:${VERSION}${tag_suffix}-${arch_label}" + + local binary_arch_label="${BINARY_ARCH_LABELS[$platform]}" + echo " Building ${tag} (${platform})..." + docker buildx build \ + --platform "$platform" \ + --tag "$tag" \ + --pull \ + --file "$dockerfile" \ + --build-arg "BINARY=dist/build/ld-relay_${VERSION}_linux_${binary_arch_label}/ld-relay" \ + $PUSH_FLAG \ + . + done + + # Create version manifest + local version_manifest="${IMAGE}:${VERSION}${tag_suffix}" + local manifest_images=() + for platform in "${platform_list[@]}"; do + local arch_label="${ARCH_LABELS[$platform]}" + manifest_images+=("${IMAGE}:${VERSION}${tag_suffix}-${arch_label}") + done + + echo " Creating manifest: ${version_manifest}" + if [[ "$DRY_RUN" == "false" ]]; then + docker manifest create "$version_manifest" "${manifest_images[@]}" --amend 2>/dev/null || \ + docker manifest create "$version_manifest" "${manifest_images[@]}" + docker manifest push "$version_manifest" + + local digest + digest=$(docker manifest inspect "$version_manifest" -v 2>/dev/null | jq -r '.digest // empty' 2>/dev/null || \ + docker buildx imagetools inspect "$version_manifest" --format '{{.Manifest.Digest}}' 2>/dev/null || echo "") + if [[ -n "$digest" ]]; then + MANIFESTS_JSON=$(echo "$MANIFESTS_JSON" | jq --arg img "$IMAGE" --arg dig "$digest" '. += [{"image": $img, "digest": $dig}]') + fi + fi + + # Alpine also gets an explicit "-alpine" alias + if [[ "$variant" == "alpine" ]]; then + local alpine_manifest="${IMAGE}:${VERSION}-alpine" + echo " Creating manifest: ${alpine_manifest}" + if [[ "$DRY_RUN" == "false" ]]; then + docker manifest create "$alpine_manifest" "${manifest_images[@]}" --amend 2>/dev/null || \ + docker manifest create "$alpine_manifest" "${manifest_images[@]}" + docker manifest push "$alpine_manifest" + fi + fi + + # Major version tag (e.g. v8, v8-static-debian12-nonroot) + if [[ "$UPDATE_MAJOR" == "true" ]]; then + local major_images=() + for platform in "${platform_list[@]}"; do + local arch_label="${ARCH_LABELS[$platform]}" + local major_tag="${IMAGE}:v${MAJOR_VERSION}${tag_suffix}-${arch_label}" + echo " Tagging ${major_tag}..." + if [[ "$DRY_RUN" == "false" ]]; then + docker buildx imagetools create --tag "$major_tag" "${IMAGE}:${VERSION}${tag_suffix}-${arch_label}" + fi + major_images+=("$major_tag") + done + + local major_manifest="${IMAGE}:v${MAJOR_VERSION}${tag_suffix}" + echo " Creating manifest: ${major_manifest}" + if [[ "$DRY_RUN" == "false" ]]; then + docker manifest create "$major_manifest" "${major_images[@]}" --amend 2>/dev/null || \ + docker manifest create "$major_manifest" "${major_images[@]}" + docker manifest push "$major_manifest" + fi + + if [[ "$variant" == "alpine" ]]; then + local alpine_major_manifest="${IMAGE}:v${MAJOR_VERSION}-alpine" + echo " Creating manifest: ${alpine_major_manifest}" + if [[ "$DRY_RUN" == "false" ]]; then + docker manifest create "$alpine_major_manifest" "${major_images[@]}" --amend 2>/dev/null || \ + docker manifest create "$alpine_major_manifest" "${major_images[@]}" + docker manifest push "$alpine_major_manifest" + fi + fi + fi + + # Latest tag + if [[ "$UPDATE_LATEST" == "true" ]]; then + local latest_images=() + for platform in "${platform_list[@]}"; do + local arch_label="${ARCH_LABELS[$platform]}" + local latest_tag="${IMAGE}:latest${tag_suffix}-${arch_label}" + echo " Tagging ${latest_tag}..." + if [[ "$DRY_RUN" == "false" ]]; then + docker buildx imagetools create --tag "$latest_tag" "${IMAGE}:${VERSION}${tag_suffix}-${arch_label}" + fi + latest_images+=("$latest_tag") + done + + local latest_manifest="${IMAGE}:latest${tag_suffix}" + echo " Creating manifest: ${latest_manifest}" + if [[ "$DRY_RUN" == "false" ]]; then + docker manifest create "$latest_manifest" "${latest_images[@]}" --amend 2>/dev/null || \ + docker manifest create "$latest_manifest" "${latest_images[@]}" + docker manifest push "$latest_manifest" + fi + + if [[ "$variant" == "alpine" ]]; then + local alpine_latest_manifest="${IMAGE}:latest-alpine" + echo " Creating manifest: ${alpine_latest_manifest}" + if [[ "$DRY_RUN" == "false" ]]; then + docker manifest create "$alpine_latest_manifest" "${latest_images[@]}" --amend 2>/dev/null || \ + docker manifest create "$alpine_latest_manifest" "${latest_images[@]}" + docker manifest push "$alpine_latest_manifest" + fi + fi + fi +} + +echo "Docker build for ld-relay v${VERSION}" +echo " Update major (v${MAJOR_VERSION}): ${UPDATE_MAJOR}" +echo " Update latest: ${UPDATE_LATEST}" +echo " Dry run: ${DRY_RUN}" + +for variant in alpine static-debian12-nonroot static-debian12-debug-nonroot; do + build_variant "$variant" +done + +# Output manifests JSON for attestation +echo "" +echo "=== Build complete ===" +if [[ "$DRY_RUN" == "false" ]]; then + echo "IMAGES_AND_DIGESTS=${MANIFESTS_JSON}" + echo "$MANIFESTS_JSON" > "$DIST_DIR/images_and_digests.json" +fi diff --git a/scripts/run-goreleaser.sh b/scripts/run-goreleaser.sh deleted file mode 100755 index b19275a8..00000000 --- a/scripts/run-goreleaser.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# run-goreleaser.sh ... -# -# Builds the Docker image and all other executables that we intend to publish. -# This also pushes the image to DockerHub unless we have specifically told it not to with -# the --skip-publish option. - -# Get the lines added to the most recent changelog update (minus the first 2 lines) -RELEASE_NOTES=`(GIT_EXTERNAL_DIFF='bash -c "diff --unchanged-line-format=\"\" $2 $5" || true' git log --ext-diff -1 --pretty= -p CHANGELOG.md)` - -# Note that we're setting GOPATH to a temporary location when running goreleaser, because -# we want it to start from a clean state even if we've previously run a build - and also -# because during a release, we may need to run this command under another account and we -# don't want to mess up file permissions in the regular GOPATH. -go run github.com/goreleaser/goreleaser/v2@v2.11.2 --clean --release-notes <(echo "${RELEASE_NOTES}") "$@" From 574012e0baaf1300818904aa72c77519ba765b4b Mon Sep 17 00:00:00 2001 From: Aaron Zeisler Date: Fri, 8 May 2026 09:06:34 -0700 Subject: [PATCH 2/5] [SDK-2337] Fix Docker Scout CI: install nfpm, load images locally, generate metadata The Docker Scout Scan CI job was failing because: 1. nfpm was not installed (build-packages.sh needs it) 2. products-for-release didn't build Docker images 3. dist/metadata.json was not generated for version extraction Fixes: - Install nfpm via go install in CI workflow - Add docker-build.sh --dry-run to products-for-release target - Use --load flag in dry-run mode so images are available locally - Generate dist/metadata.json in cross-compile.sh Co-authored-by: Cursor --- .github/workflows/ci.yml | 3 +++ Makefile | 1 + scripts/cross-compile.sh | 2 ++ scripts/docker-build.sh | 5 +++-- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 080e5217..7c64cc0d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,6 +75,9 @@ jobs: uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 with: platforms: linux/amd64,linux/arm64/v8,linux/arm/v7,linux/386 + driver-opts: network=host + - name: Install nfpm + run: go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest - name: Build Docker Images run: make products-for-release - name: Get current Relay version diff --git a/Makefile b/Makefile index a23f6105..443c6448 100644 --- a/Makefile +++ b/Makefile @@ -67,6 +67,7 @@ publish: products-for-release: ./scripts/cross-compile.sh --keep-build ./scripts/build-packages.sh + ./scripts/docker-build.sh --dry-run DOCKER_COMPOSE_TEST=docker-compose -f docker-compose.test.yml diff --git a/scripts/cross-compile.sh b/scripts/cross-compile.sh index 1b78dcff..ad200ede 100755 --- a/scripts/cross-compile.sh +++ b/scripts/cross-compile.sh @@ -74,6 +74,8 @@ echo "Generating checksums..." cd "$DIST_DIR" shasum -a 256 *.tar.gz > checksums.txt +echo "{\"version\":\"$VERSION\"}" > "$DIST_DIR/metadata.json" + if [[ "$KEEP_BUILD" == "false" ]]; then rm -rf "$DIST_DIR/build" fi diff --git a/scripts/docker-build.sh b/scripts/docker-build.sh index 76e03e39..68afcc3a 100755 --- a/scripts/docker-build.sh +++ b/scripts/docker-build.sh @@ -62,8 +62,9 @@ declare -A BINARY_ARCH_LABELS=( ["linux/386"]="386" ) -PUSH_FLAG="" -if [[ "$DRY_RUN" == "false" ]]; then +if [[ "$DRY_RUN" == "true" ]]; then + PUSH_FLAG="--load" +else PUSH_FLAG="--push" fi From 094a28e1fb56e5b1c5d55c5bd34830496550a0a9 Mon Sep 17 00:00:00 2001 From: Aaron Zeisler Date: Fri, 8 May 2026 09:47:52 -0700 Subject: [PATCH 3/5] [SDK-2337] Fix nfpm.yml: use 'depends' instead of 'dependencies' Standalone nfpm uses 'depends' for package dependencies under overrides, not 'dependencies' (which is the GoReleaser-embedded nfpm syntax). Co-authored-by: Cursor --- nfpm.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nfpm.yml b/nfpm.yml index 9522644c..2f678146 100644 --- a/nfpm.yml +++ b/nfpm.yml @@ -25,8 +25,8 @@ contents: overrides: deb: - dependencies: + depends: - upstart rpm: - dependencies: + depends: - systemd From 95211d46b6501ca5bd98b76f738ea26b9097356d Mon Sep 17 00:00:00 2001 From: Aaron Zeisler Date: Fri, 8 May 2026 10:33:48 -0700 Subject: [PATCH 4/5] [SDK-2337] fix: use envsubst for nfpm config variable expansion nfpm does not expand environment variables in contents[].src paths. Pre-process nfpm.yml through envsubst before passing to nfpm to ensure VERSION and NFPM_ARCH_LABEL are properly substituted. Co-authored-by: Cursor --- scripts/build-packages.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/scripts/build-packages.sh b/scripts/build-packages.sh index 5b3783a5..25a0878a 100755 --- a/scripts/build-packages.sh +++ b/scripts/build-packages.sh @@ -44,13 +44,16 @@ done for entry in "${ARCHS[@]}"; do IFS=':' read -r nfpm_arch arch_label <<< "$entry" + # nfpm doesn't expand env vars in contents[].src paths, so we use envsubst + export NFPM_ARCH="$nfpm_arch" NFPM_ARCH_LABEL="$arch_label" VERSION="$VERSION" + expanded_config=$(envsubst < "$PROJECT_ROOT/nfpm.yml") + for format in deb rpm; do echo " ${format} (${arch_label})..." - NFPM_ARCH="$nfpm_arch" NFPM_ARCH_LABEL="$arch_label" VERSION="$VERSION" \ - nfpm package \ - --config "$PROJECT_ROOT/nfpm.yml" \ - --packager "$format" \ - --target "$DIST_DIR/" + nfpm package \ + --config /dev/stdin \ + --packager "$format" \ + --target "$DIST_DIR/" <<< "$expanded_config" done done From 2a21cb9a2f3fe758c03d535c718197008b632843 Mon Sep 17 00:00:00 2001 From: Aaron Zeisler Date: Thu, 28 May 2026 11:07:14 -0700 Subject: [PATCH 5/5] [SDK-2337] refactor: consolidate release steps into single release.sh script - Create scripts/release.sh as a single entry point that orchestrates cross-compile, build-packages, and docker-build in sequence. - Remove unnecessary BINARY ARG from Dockerfiles; instead pass the binary's directory as the Docker build context so the existing COPY ld-relay instruction works unchanged. - Simplify publish action.yml from multiple steps to one. - Simplify Makefile publish/products-for-release to one-liners. Co-authored-by: Cursor --- .github/actions/publish/action.yml | 24 ++++--------------- ...e-static-debian12-debug-nonroot.goreleaser | 4 +--- Dockerfile-static-debian12-nonroot.goreleaser | 4 +--- Dockerfile.goreleaser | 4 +--- Makefile | 8 ++----- scripts/docker-build.sh | 4 ++-- scripts/release.sh | 22 +++++++++++++++++ 7 files changed, 33 insertions(+), 37 deletions(-) create mode 100755 scripts/release.sh diff --git a/.github/actions/publish/action.yml b/.github/actions/publish/action.yml index ba9ac6ac..04ca6fcb 100644 --- a/.github/actions/publish/action.yml +++ b/.github/actions/publish/action.yml @@ -42,31 +42,15 @@ runs: run: | echo $DOCKER_TOKEN | docker login --username $DOCKER_USERNAME --password-stdin - - name: Extract version from tag - id: version - shell: bash - run: | - TAG="${{ inputs.tag }}" - VERSION="${TAG#v}" - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - - - name: Cross-compile binaries - shell: bash - run: | - ./scripts/cross-compile.sh --keep-build "${{ steps.version.outputs.version }}" - - - name: Build system packages - shell: bash - run: | - ./scripts/build-packages.sh "${{ steps.version.outputs.version }}" - - - name: Build and push Docker images + - name: Build release artifacts shell: bash env: LD_RELEASER_UPDATE_MAJOR: ${{ inputs.update-major-tag }} LD_RELEASER_UPDATE_LATEST: ${{ inputs.update-latest-tag }} run: | - ./scripts/docker-build.sh ${{ inputs.dry-run == 'true' && '--dry-run' || '' }} "${{ steps.version.outputs.version }}" + TAG="${{ inputs.tag }}" + VERSION="${TAG#v}" + ./scripts/release.sh ${{ inputs.dry-run == 'true' && '--dry-run' || '' }} "$VERSION" - name: Output checksum file path id: binary diff --git a/Dockerfile-static-debian12-debug-nonroot.goreleaser b/Dockerfile-static-debian12-debug-nonroot.goreleaser index d1c5cd60..6e416cc1 100644 --- a/Dockerfile-static-debian12-debug-nonroot.goreleaser +++ b/Dockerfile-static-debian12-debug-nonroot.goreleaser @@ -3,9 +3,7 @@ FROM gcr.io/distroless/static-debian12:debug-nonroot # See "Runtime platform versions" in CONTRIBUTING.md -ARG BINARY=ld-relay - -COPY ${BINARY} /usr/bin/ldr +COPY ld-relay /usr/bin/ldr EXPOSE 8030 ENV PORT=8030 diff --git a/Dockerfile-static-debian12-nonroot.goreleaser b/Dockerfile-static-debian12-nonroot.goreleaser index c2328c9f..1946810f 100644 --- a/Dockerfile-static-debian12-nonroot.goreleaser +++ b/Dockerfile-static-debian12-nonroot.goreleaser @@ -3,9 +3,7 @@ FROM gcr.io/distroless/static-debian12:nonroot # See "Runtime platform versions" in CONTRIBUTING.md -ARG BINARY=ld-relay - -COPY ${BINARY} /usr/bin/ldr +COPY ld-relay /usr/bin/ldr EXPOSE 8030 ENV PORT=8030 diff --git a/Dockerfile.goreleaser b/Dockerfile.goreleaser index 5c3a7558..7281bda8 100644 --- a/Dockerfile.goreleaser +++ b/Dockerfile.goreleaser @@ -3,15 +3,13 @@ FROM alpine:3.23.4 # See "Runtime platform versions" in CONTRIBUTING.md -ARG BINARY=ld-relay - RUN apk add --no-cache \ ca-certificates \ && apk add --upgrade libcrypto3 libssl3 \ && update-ca-certificates \ && rm -rf /var/cache/apk/* -COPY ${BINARY} /usr/bin/ldr +COPY ld-relay /usr/bin/ldr RUN addgroup -g 1000 -S ldr-user && \ adduser -u 1000 -S ldr-user -G ldr-user && \ diff --git a/Makefile b/Makefile index 443c6448..ae4b271f 100644 --- a/Makefile +++ b/Makefile @@ -60,14 +60,10 @@ echo-release-notes: @cat $(RELEASE_NOTES) publish: - ./scripts/cross-compile.sh --keep-build - ./scripts/build-packages.sh - ./scripts/docker-build.sh + ./scripts/release.sh products-for-release: - ./scripts/cross-compile.sh --keep-build - ./scripts/build-packages.sh - ./scripts/docker-build.sh --dry-run + ./scripts/release.sh --dry-run DOCKER_COMPOSE_TEST=docker-compose -f docker-compose.test.yml diff --git a/scripts/docker-build.sh b/scripts/docker-build.sh index 68afcc3a..1beefa92 100755 --- a/scripts/docker-build.sh +++ b/scripts/docker-build.sh @@ -100,15 +100,15 @@ build_variant() { local tag="${IMAGE}:${VERSION}${tag_suffix}-${arch_label}" local binary_arch_label="${BINARY_ARCH_LABELS[$platform]}" + local build_context="$DIST_DIR/build/ld-relay_${VERSION}_linux_${binary_arch_label}" echo " Building ${tag} (${platform})..." docker buildx build \ --platform "$platform" \ --tag "$tag" \ --pull \ --file "$dockerfile" \ - --build-arg "BINARY=dist/build/ld-relay_${VERSION}_linux_${binary_arch_label}/ld-relay" \ $PUSH_FLAG \ - . + "$build_context" done # Create version manifest diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 00000000..37e8a9d9 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Orchestrates the full release pipeline: cross-compile, package, and Docker build. +# +# Usage: ./scripts/release.sh [--dry-run] [VERSION] +# --dry-run: Build artifacts locally without pushing Docker images or uploading releases. +# VERSION defaults to the value in relay/version/version.go. + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +DRY_RUN="" +if [[ "${1:-}" == "--dry-run" ]]; then + DRY_RUN="--dry-run" + shift +fi + +VERSION="${1:-}" + +"$SCRIPT_DIR/cross-compile.sh" --keep-build ${VERSION:+"$VERSION"} +"$SCRIPT_DIR/build-packages.sh" ${VERSION:+"$VERSION"} +"$SCRIPT_DIR/docker-build.sh" $DRY_RUN ${VERSION:+"$VERSION"}