Skip to content

Sync from Copyberry #289

Sync from Copyberry

Sync from Copyberry #289

Workflow file for this run

name: release
on:
push:
branches:
- master
tags:
- "v*" # release tags must be v<semver>
permissions:
contents: read
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
env:
GO_VERSION: "1.26.x"
GOPROXY: https://proxy.golang.org
MODULE_PATH: github.com/openai/tunnel-client
BINARY_NAME: tunnel-client
PUBLIC_STORAGE_ACCOUNT: prod1pstatic
PUBLIC_STORAGE_CONTAINER: persistent
PUBLIC_BUCKET_PREFIX: tunnel-client
PUBLIC_BASE_URL_ROOT: https://persistent.oaistatic.com
AZURE_TENANT_ID: a48cca56-e6da-484e-a814-9c849652bcb3
AZURE_CLIENT_ID: 14c0c62b-2f5a-4a7f-aaca-bfbc980645fa
AZURE_SUBSCRIPTION_ID: c24a3833-f66c-4c0b-8263-91c5cc408ff9
jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Validate release tag
if: ${{ github.ref_type == 'tag' }}
run: |
./scripts/release_tag.sh parse "${GITHUB_REF_NAME}"
./scripts/release_tag.sh check-source-version "${GITHUB_REF_NAME}"
- name: Test release tag tooling
run: bash ./scripts/release_tag_test.sh
- name: Validate bundled cloudflared manifest
run: |
set -euo pipefail
./scripts/build_cloudflared.sh --describe --goos linux --goarch amd64
./scripts/build_cloudflared.sh --describe --goos linux --goarch arm64
./scripts/build_cloudflared.sh --describe --goos darwin --goarch amd64
./scripts/build_cloudflared.sh --describe --goos darwin --goarch arm64
./scripts/build_cloudflared.sh --describe --goos windows --goarch amd64
./scripts/build_cloudflared.sh --describe --goos windows --goarch arm64
- name: Validate
run: |
go env
go mod download
go test ./...
build:
name: Build (${{ matrix.goos }}/${{ matrix.goarch }})
needs: test
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- goos: linux
goarch: amd64
ext: ""
- goos: linux
goarch: arm64
ext: ""
- goos: darwin
goarch: amd64
ext: ""
- goos: darwin
goarch: arm64
ext: ""
- goos: windows
goarch: amd64
ext: ".exe"
- goos: windows
goarch: arm64
ext: ".exe"
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Build
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: 0
TAG: ${{ github.ref_name }}
run: |
set -euo pipefail
mkdir -p dist/public dist/package-input
BIN_NAME=${{ env.BINARY_NAME }}${{ matrix.ext }}
LDFLAGS="-s -w -X ${{ env.MODULE_PATH }}/pkg/version.GitSHA=${GITHUB_SHA}"
ASSET_TAG="${GITHUB_SHA::12}"
if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
eval "$(./scripts/release_tag.sh parse "${TAG}")"
LDFLAGS="${LDFLAGS} -X ${{ env.MODULE_PATH }}/pkg/version.semanticVersion=${release_version}"
ASSET_TAG="${release_tag}"
fi
GOFLAGS="-trimpath -buildvcs=false"
RAW_BINARY_NAME=${{ env.BINARY_NAME }}-${ASSET_TAG}-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.ext }}
CLOUDFLARED_RAW_NAME=cloudflared-${ASSET_TAG}-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.ext }}
go build $GOFLAGS -ldflags "$LDFLAGS" -o "dist/package-input/$RAW_BINARY_NAME" ./cmd/client
./scripts/build_cloudflared.sh \
--goos "${{ matrix.goos }}" \
--goarch "${{ matrix.goarch }}" \
--output "dist/package-input/$CLOUDFLARED_RAW_NAME"
if [[ "${GITHUB_REF_TYPE}" == "tag" && "${{ matrix.goos }}" == "linux" && "${{ matrix.goarch }}" == "amd64" ]]; then
expected_version="${release_version}+${GITHUB_SHA} (git sha: ${GITHUB_SHA})"
actual_version="$("dist/package-input/$RAW_BINARY_NAME" --version)"
if [[ "${actual_version}" != "${expected_version}" ]]; then
echo "release binary version mismatch" >&2
printf 'expected: %s\n' "${expected_version}" >&2
printf 'actual: %s\n' "${actual_version}" >&2
exit 1
fi
fi
if [[ "${{ matrix.goos }}" == "linux" && "${{ matrix.goarch }}" == "amd64" ]]; then
expected_cloudflared_version="$(python3 -c 'import json; print(json.load(open("pkg/cloudflared/manifest.json"))["version"])')"
actual_cloudflared_version="$("dist/package-input/$CLOUDFLARED_RAW_NAME" --version)"
if [[ "${actual_cloudflared_version}" != *"${expected_cloudflared_version}"* ]]; then
echo "bundled cloudflared version mismatch" >&2
printf 'expected substring: %s\n' "${expected_cloudflared_version}" >&2
printf 'actual: %s\n' "${actual_cloudflared_version}" >&2
exit 1
fi
fi
if [[ "${{ matrix.goos }}" == "windows" && "${{ matrix.goarch }}" == "arm64" ]]; then
expected_cloudflared_version="$(python3 -c 'import json; print(json.load(open("pkg/cloudflared/manifest.json"))["version"])')"
if ! grep -a -Fq "${expected_cloudflared_version}" "dist/package-input/$CLOUDFLARED_RAW_NAME"; then
echo "proxy-built cloudflared does not embed the pinned version" >&2
exit 1
fi
fi
# Package as zip with OS/Arch/Tag in name
ASSET_NAME=${{ env.BINARY_NAME }}-${ASSET_TAG}-${{ matrix.goos }}-${{ matrix.goarch }}
stage_dir="$(mktemp -d)"
cp "dist/package-input/$RAW_BINARY_NAME" "$stage_dir/$BIN_NAME"
cp "dist/package-input/$CLOUDFLARED_RAW_NAME" "$stage_dir/cloudflared${{ matrix.ext }}"
cp "pkg/cloudflared/manifest.json" "$stage_dir/cloudflared-manifest.json"
cp "LICENSE" "$stage_dir/LICENSE"
(cd "$stage_dir" && zip -9 "${GITHUB_WORKSPACE}/dist/public/$ASSET_NAME.zip" "$BIN_NAME" "cloudflared${{ matrix.ext }}" cloudflared-manifest.json LICENSE)
rm -rf "$stage_dir"
- name: Upload artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: release-assets-${{ matrix.goos }}-${{ matrix.goarch }}
path: dist/**
if-no-files-found: error
release:
name: Release
if: startsWith(github.ref, 'refs/tags/')
needs: build
runs-on: macos-latest
permissions:
actions: read
contents: write
id-token: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Derive release metadata
id: release_meta
run: |
while IFS='=' read -r key value; do
echo "${key}=${value}" >> "${GITHUB_OUTPUT}"
done < <(./scripts/release_tag.sh parse "${GITHUB_REF_NAME}")
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: release-assets-*
merge-multiple: true
path: dist
- name: Build combined distribution packages
run: |
./scripts/build_distribution_package.sh \
--tag "${GITHUB_REF_NAME}" \
--binary-dir dist/package-input \
--output-dir dist/public
- name: Generate SHA256 checksums
working-directory: dist/public
run: |
shopt -s nullglob
if command -v sha256sum >/dev/null 2>&1; then
sha256sum *.zip *.tar.gz > SHA256SUMS.txt
else
shasum -a 256 *.zip *.tar.gz > SHA256SUMS.txt
fi
- name: Generate public URLs
working-directory: dist/public
env:
PUBLIC_BASE_URL: ${{ steps.release_meta.outputs.public_base_url }}
run: |
{
for file in *.zip *.tar.gz SHA256SUMS.txt; do
printf '%s/%s\n' "${PUBLIC_BASE_URL}" "${file}"
done
} > PUBLIC_URLS.txt
- name: Verify Azure CLI on macOS
run: |
set -euo pipefail
command -v az
az version
- name: Azure login for public artifact upload
uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0
with:
tenant-id: ${{ env.AZURE_TENANT_ID }}
client-id: ${{ env.AZURE_CLIENT_ID }}
subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }}
- name: Upload public artifacts
run: |
az storage blob upload-batch \
--subscription "${AZURE_SUBSCRIPTION_ID}" \
--account-name "${PUBLIC_STORAGE_ACCOUNT}" \
--destination "${PUBLIC_STORAGE_CONTAINER}" \
--destination-path "${{ steps.release_meta.outputs.public_blob_path }}" \
--source dist/public \
--auth-mode login \
--overwrite true
- name: Verify public artifact URLs
working-directory: dist/public
run: |
while IFS= read -r url; do
for attempt in 1 2 3 4 5; do
if curl -fsSI "${url}" >/dev/null; then
break
fi
if [[ "${attempt}" -eq 5 ]]; then
echo "failed to verify ${url}" >&2
exit 1
fi
sleep 2
done
done < PUBLIC_URLS.txt
# Optional signing:
# - name: Import GPG key
# if: ${{ secrets.GPG_PRIVATE_KEY && secrets.GPG_PASSPHRASE }}
# run: |
# echo "$GPG_PRIVATE_KEY" | gpg --batch --yes --import
# env:
# GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
# - name: Sign checksums
# if: ${{ secrets.GPG_PRIVATE_KEY && secrets.GPG_PASSPHRASE }}
# working-directory: dist
# env:
# PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
# run: |
# echo "$PASSPHRASE" | gpg --batch --yes --pinentry-mode loopback --passphrase-fd 0 \
# --armor --detach-sign --output SHA256SUMS.txt.asc SHA256SUMS.txt
- name: Create GitHub Release
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2
with:
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
draft: false
prerelease: ${{ steps.release_meta.outputs.prerelease == 'true' }}
generate_release_notes: true
files: |
dist/public/*.zip
dist/public/*.tar.gz
dist/public/SHA256SUMS.txt
dist/public/PUBLIC_URLS.txt