From 624c83407b954b04dfd7aac3456fe469aca543ad Mon Sep 17 00:00:00 2001 From: Matjaz Pirnovar Date: Thu, 16 Jul 2026 13:36:16 -0700 Subject: [PATCH 1/2] [FSSDK-12919] Replace deprecated hub CLI with gh in release workflow Agent GitHub releases were shipping with no binary assets because the release workflow attached generate_secret via the deprecated `hub` CLI, which is not installed on GitHub-hosted runners (hub: command not found). Replace `hub` with `gh` (preinstalled on all runners): - ci_attach_generate_secret.sh: `hub release edit -a` -> `gh release upload --clobber` - new ci_create_github_release.sh: gh-based, idempotent replacement for travisci-tools/release_github_v2.sh (same CHANGELOG parsing) - workflow: drop install_hub.sh steps + unused travisci-tools checkouts; `hub release download -i` -> `gh release download -p` https://optimizely-ext.atlassian.net/browse/FSSDK-12919 Co-Authored-By: Claude Opus 4.8 --- .github/workflows/agent.yml | 41 +++---------------- scripts/ci_attach_generate_secret.sh | 11 ++++-- scripts/ci_create_github_release.sh | 59 ++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 40 deletions(-) create mode 100755 scripts/ci_create_github_release.sh diff --git a/.github/workflows/agent.yml b/.github/workflows/agent.yml index 8d761f8f..e2f45f1f 100644 --- a/.github/workflows/agent.yml +++ b/.github/workflows/agent.yml @@ -170,14 +170,6 @@ jobs: with: go-version: '1.24.0' check-latest: true - - uses: actions/checkout@v2 - with: - # You should create a personal access token and store it in your repository - token: ${{ secrets.CI_USER_TOKEN }} - repository: 'optimizely/travisci-tools' - path: 'home/runner/travisci-tools' - ref: 'master' - persist-credentials: false - name: Get the version id: get_version run: echo "VERSION=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT @@ -190,20 +182,13 @@ jobs: echo "APP_VERSION=${TAG#v}" >> $GITHUB_ENV echo "RELEASE_TAG=${TAG}" >> $GITHUB_ENV echo "TRAVIS_BUILD_DIR=${{ steps.get_workspace.outputs.WORKSPACE }}" >> $GITHUB_ENV - - name: Upload and publish draft - env: - HOME: 'home/runner' - run: | - # installs hub to ~/bin - $HOME/travisci-tools/release_github/install_hub.sh - echo "$HOME/bin:$HOME/travisci-tools/release_github" >> $GITHUB_PATH - name: run make env: TRAVIS_OS_NAME: 'linux' run: | make -e setup build - name: create and upload packages - env: + env: HOME: 'home/runner' GITHUB_TOKEN: ${{ secrets.CI_USER_TOKEN }} TRAVIS_OS_NAME: 'linux' @@ -212,9 +197,8 @@ jobs: run: | # now we're going to create packages & upload packages ./scripts/ci_create_packages.sh && ./scripts/ci_upload_packages.sh - # create the github release (draft) - cp $HOME/travisci-tools/release_github/release_github_v2.sh . - ./release_github_v2.sh "$APP_VERSION" + # create the github release (draft) if it doesn't already exist + ./scripts/ci_create_github_release.sh "$RELEASE_TAG" # attach generate_secret to the github release ./scripts/ci_build_generate_secret.sh && ./scripts/ci_attach_generate_secret.sh @@ -244,14 +228,6 @@ jobs: with: go-version: '1.24.0' check-latest: true - - uses: actions/checkout@v2 - with: - # You should create a personal access token and store it in your repository - token: ${{ secrets.CI_USER_TOKEN }} - repository: 'optimizely/travisci-tools' - path: 'home/runner/travisci-tools' - ref: 'master' - persist-credentials: false - name: Get the version id: get_version run: echo "VERSION=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT @@ -259,14 +235,6 @@ jobs: run: | TAG=${{ steps.get_version.outputs.VERSION }} echo "APP_VERSION=${TAG#v}" >> $GITHUB_ENV - - name: Upload and publish draft - shell: bash - env: - HOME: 'home/runner' - run: | - # installs hub to ~/bin - $HOME/travisci-tools/release_github/install_hub.sh - # echo "$HOME/bin:$HOME/travisci-tools/slack" >> $GITHUB_PATH - name: run script env: GITHUB_TOKEN: ${{ secrets.CI_USER_TOKEN }} @@ -276,7 +244,8 @@ jobs: id: script shell: bash run: | - hub release download $(git describe --abbrev=0 --tags) -i '*-${{ matrix.TARGET }}-*' + # gh is preinstalled on GitHub-hosted runners; replaces the deprecated hub CLI + gh release download $(git describe --abbrev=0 --tags) -p '*-${{ matrix.TARGET }}-*' tar xvfz generate_secret-${{ matrix.TARGET }}-${APP_VERSION}.tar.gz -C /tmp /tmp/generate_secret # TODO: add step to publish outcome on teams. diff --git a/scripts/ci_attach_generate_secret.sh b/scripts/ci_attach_generate_secret.sh index f4035343..6d73ed8b 100755 --- a/scripts/ci_attach_generate_secret.sh +++ b/scripts/ci_attach_generate_secret.sh @@ -1,7 +1,10 @@ #!/usr/bin/env bash set -e -hub release edit "$RELEASE_TAG" -m "" \ - -a "/tmp/output_packages/generate_secret-linux-amd64-$APP_VERSION.tar.gz#generate_secret $APP_VERSION for Linux 64-bit" \ - -a "/tmp/output_packages/generate_secret-darwin-amd64-$APP_VERSION.tar.gz#generate_secret $APP_VERSION for MacOS 64-bit" \ - -a "/tmp/output_packages/generate_secret-windows-amd64-$APP_VERSION.tar.gz#generate_secret $APP_VERSION for Windows 64-bit" +# Attaches the generate_secret binaries to the GitHub release for $RELEASE_TAG. +# Uses `gh` (preinstalled on GitHub-hosted runners) instead of the deprecated `hub` CLI. +# `gh release upload` supports per-asset display labels via the "path#label" syntax. +gh release upload "$RELEASE_TAG" --clobber \ + "/tmp/output_packages/generate_secret-linux-amd64-$APP_VERSION.tar.gz#generate_secret $APP_VERSION for Linux 64-bit" \ + "/tmp/output_packages/generate_secret-darwin-amd64-$APP_VERSION.tar.gz#generate_secret $APP_VERSION for MacOS 64-bit" \ + "/tmp/output_packages/generate_secret-windows-amd64-$APP_VERSION.tar.gz#generate_secret $APP_VERSION for Windows 64-bit" diff --git a/scripts/ci_create_github_release.sh b/scripts/ci_create_github_release.sh new file mode 100755 index 00000000..2eb3c7a0 --- /dev/null +++ b/scripts/ci_create_github_release.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -o pipefail + +# Creates a draft GitHub release for the given tag, using the latest +# CHANGELOG.md entry as the release description. +# +# This is a `gh`-based replacement for travisci-tools/release_github/release_github_v2.sh, +# which relied on the deprecated `hub` CLI. `gh` is preinstalled on GitHub-hosted runners. +# +# Run this in the same directory where CHANGELOG.md lives. +# grep -P below is GNU grep specific, so this is meant to run on Linux. + +CHANGELOG="CHANGELOG.md" + +# the tag being released, e.g. v4.6.0 +GIT_TAG="$1" + +# set to true for debugging +debug=false + +if [ $# -ne 1 ]; then + echo "example: $0 v3.1.1" + exit 1 +fi + +# VERSION is the git tag with the "v" prefix removed +VERSION=${GIT_TAG#v} + +# The release is often already created (the tag push that triggers CI usually +# comes from a GitHub release created in the UI). In that case there is nothing +# to create -- just let the caller move on to uploading assets. +if gh release view "${GIT_TAG}" >/dev/null 2>&1; then + echo "Release ${GIT_TAG} already exists; skipping creation." + exit 0 +fi + +# check that CHANGELOG.md has been updated +# (first version entry in the changelog should match our VERSION argument) +NEW_VERSION_CHECK=$(grep -P '^## \[\d+\.\d+\.\d+\]' ${CHANGELOG} | cut -d[ -f2 | cut -d] -f1 | awk 'NR==1') + +$debug && echo "NEW_VERSION_CHECK $NEW_VERSION_CHECK" +$debug && echo "VERSION $VERSION" + +if [[ "${NEW_VERSION_CHECK}" != "${VERSION}" ]]; then + echo "ERROR: ${CHANGELOG} has not been updated yet." + exit 1 +fi + +NEW_VERSION=$(grep -P '^## \[\d+\.\d+\.\d+\]' ${CHANGELOG} | awk 'NR==1' | sed -e 's/\[/\\\[/' | sed -e 's/\]/\\\]/') +LAST_VERSION=$(grep -P '^## \[\d+\.\d+\.\d+\]' ${CHANGELOG} | awk 'NR==2' | sed -e 's/\[/\\\[/' | sed -e 's/\]/\\\]/') + +DESCRIPTION=$(awk "/^${NEW_VERSION}$/,/^${LAST_VERSION:-nothingmatched}$/" "${CHANGELOG}" | grep -v "^${LAST_VERSION:-nothingmatched}$") + +$debug && echo "NEW_VERSION $NEW_VERSION" +$debug && echo "LAST_VERSION $LAST_VERSION" +$debug && echo "DESCRIPTION $DESCRIPTION" + +# --draft creates a draft release; the tag already exists (release is triggered by the tag push) +gh release create "${GIT_TAG}" --draft --title "Release ${VERSION}" --notes "${DESCRIPTION}" From c955a67ca172b87deb797596e8e214fc834646f9 Mon Sep 17 00:00:00 2001 From: Matjaz Pirnovar Date: Thu, 16 Jul 2026 14:20:11 -0700 Subject: [PATCH 2/2] [FSSDK-12919] Address review: harden release script, drop unused HOME - ci_create_github_release.sh: set -eo pipefail; guard missing CHANGELOG.md; quote CHANGELOG; write notes to a temp file and use --notes-file so backticks/$ in the changelog body aren't shell-parsed - agent.yml: remove now-unused HOME='home/runner' override Co-Authored-By: Claude Opus 4.8 --- .github/workflows/agent.yml | 1 - scripts/ci_create_github_release.sh | 27 +++++++++++++++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/.github/workflows/agent.yml b/.github/workflows/agent.yml index e2f45f1f..fc3033e5 100644 --- a/.github/workflows/agent.yml +++ b/.github/workflows/agent.yml @@ -189,7 +189,6 @@ jobs: make -e setup build - name: create and upload packages env: - HOME: 'home/runner' GITHUB_TOKEN: ${{ secrets.CI_USER_TOKEN }} TRAVIS_OS_NAME: 'linux' DOCKERHUB_PASS: ${{ secrets.DOCKERHUB_PASS }} diff --git a/scripts/ci_create_github_release.sh b/scripts/ci_create_github_release.sh index 2eb3c7a0..bc76c110 100755 --- a/scripts/ci_create_github_release.sh +++ b/scripts/ci_create_github_release.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -set -o pipefail +set -eo pipefail # Creates a draft GitHub release for the given tag, using the latest # CHANGELOG.md entry as the release description. @@ -12,9 +12,6 @@ set -o pipefail CHANGELOG="CHANGELOG.md" -# the tag being released, e.g. v4.6.0 -GIT_TAG="$1" - # set to true for debugging debug=false @@ -23,6 +20,9 @@ if [ $# -ne 1 ]; then exit 1 fi +# the tag being released, e.g. v4.6.0 +GIT_TAG="$1" + # VERSION is the git tag with the "v" prefix removed VERSION=${GIT_TAG#v} @@ -34,9 +34,14 @@ if gh release view "${GIT_TAG}" >/dev/null 2>&1; then exit 0 fi +if [[ ! -f "${CHANGELOG}" ]]; then + echo "ERROR: ${CHANGELOG} not found in $(pwd)." + exit 1 +fi + # check that CHANGELOG.md has been updated # (first version entry in the changelog should match our VERSION argument) -NEW_VERSION_CHECK=$(grep -P '^## \[\d+\.\d+\.\d+\]' ${CHANGELOG} | cut -d[ -f2 | cut -d] -f1 | awk 'NR==1') +NEW_VERSION_CHECK=$(grep -P '^## \[\d+\.\d+\.\d+\]' "${CHANGELOG}" | cut -d[ -f2 | cut -d] -f1 | awk 'NR==1') $debug && echo "NEW_VERSION_CHECK $NEW_VERSION_CHECK" $debug && echo "VERSION $VERSION" @@ -46,8 +51,8 @@ if [[ "${NEW_VERSION_CHECK}" != "${VERSION}" ]]; then exit 1 fi -NEW_VERSION=$(grep -P '^## \[\d+\.\d+\.\d+\]' ${CHANGELOG} | awk 'NR==1' | sed -e 's/\[/\\\[/' | sed -e 's/\]/\\\]/') -LAST_VERSION=$(grep -P '^## \[\d+\.\d+\.\d+\]' ${CHANGELOG} | awk 'NR==2' | sed -e 's/\[/\\\[/' | sed -e 's/\]/\\\]/') +NEW_VERSION=$(grep -P '^## \[\d+\.\d+\.\d+\]' "${CHANGELOG}" | awk 'NR==1' | sed -e 's/\[/\\\[/' | sed -e 's/\]/\\\]/') +LAST_VERSION=$(grep -P '^## \[\d+\.\d+\.\d+\]' "${CHANGELOG}" | awk 'NR==2' | sed -e 's/\[/\\\[/' | sed -e 's/\]/\\\]/') DESCRIPTION=$(awk "/^${NEW_VERSION}$/,/^${LAST_VERSION:-nothingmatched}$/" "${CHANGELOG}" | grep -v "^${LAST_VERSION:-nothingmatched}$") @@ -55,5 +60,11 @@ $debug && echo "NEW_VERSION $NEW_VERSION" $debug && echo "LAST_VERSION $LAST_VERSION" $debug && echo "DESCRIPTION $DESCRIPTION" +# Write the notes to a temp file and pass via --notes-file. This avoids the shell +# re-parsing backticks / $ that can appear in changelog bodies (which --notes would). +NOTES_FILE=$(mktemp) +trap 'rm -f "${NOTES_FILE}"' EXIT +printf '%s\n' "${DESCRIPTION}" > "${NOTES_FILE}" + # --draft creates a draft release; the tag already exists (release is triggered by the tag push) -gh release create "${GIT_TAG}" --draft --title "Release ${VERSION}" --notes "${DESCRIPTION}" +gh release create "${GIT_TAG}" --draft --title "Release ${VERSION}" --notes-file "${NOTES_FILE}"