From 651b447522f5b402408a48b4945352c49dd70773 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 16 May 2026 15:08:49 +0000 Subject: [PATCH 1/4] Initial plan From 271eb2e4fe9f46bfc0d72cfedc465e0bd18bad68 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 16 May 2026 15:12:25 +0000 Subject: [PATCH 2/4] Add workflow to keep release download alias updated --- .github/workflows/release-download-alias.yml | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/release-download-alias.yml diff --git a/.github/workflows/release-download-alias.yml b/.github/workflows/release-download-alias.yml new file mode 100644 index 0000000..a568b8d --- /dev/null +++ b/.github/workflows/release-download-alias.yml @@ -0,0 +1,37 @@ +name: Maintain release download alias + +on: + release: + types: + - published + workflow_dispatch: + inputs: + source_tag: + description: Tag to mirror into the rolling "release" download URL + required: true + +permissions: + contents: write + +jobs: + update-release-alias: + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ github.token }} + REPOSITORY: ${{ github.repository }} + SOURCE_TAG: ${{ github.event_name == 'release' && github.event.release.tag_name || github.event.inputs.source_tag }} + steps: + - name: Download pict.exe from source release + run: gh release download "$SOURCE_TAG" --repo "$REPOSITORY" --pattern pict.exe --clobber + + - name: Recreate rolling release alias + run: | + if gh release view release --repo "$REPOSITORY" >/dev/null 2>&1; then + gh release delete release --repo "$REPOSITORY" --yes --cleanup-tag + fi + + gh release create release pict.exe \ + --repo "$REPOSITORY" \ + --target "$SOURCE_TAG" \ + --title "Latest release" \ + --notes "Rolling release that keeps https://github.com/$REPOSITORY/releases/download/release/pict.exe pointed at the newest published binary." From 542fdef731190b420f277a3cea3dc89f1a147e30 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 16 May 2026 15:19:51 +0000 Subject: [PATCH 3/4] Mirror all release assets in rolling alias workflow --- .github/workflows/release-download-alias.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-download-alias.yml b/.github/workflows/release-download-alias.yml index a568b8d..29703e1 100644 --- a/.github/workflows/release-download-alias.yml +++ b/.github/workflows/release-download-alias.yml @@ -21,16 +21,25 @@ jobs: REPOSITORY: ${{ github.repository }} SOURCE_TAG: ${{ github.event_name == 'release' && github.event.release.tag_name || github.event.inputs.source_tag }} steps: - - name: Download pict.exe from source release - run: gh release download "$SOURCE_TAG" --repo "$REPOSITORY" --pattern pict.exe --clobber + - name: Download release assets from source release + run: | + mkdir -p release-assets + gh release download "$SOURCE_TAG" --repo "$REPOSITORY" --pattern "*" --dir release-assets --clobber - name: Recreate rolling release alias run: | + shopt -s nullglob + assets=(release-assets/*) + if [ ${#assets[@]} -eq 0 ]; then + echo "No assets were found on release $SOURCE_TAG." + exit 1 + fi + if gh release view release --repo "$REPOSITORY" >/dev/null 2>&1; then gh release delete release --repo "$REPOSITORY" --yes --cleanup-tag fi - gh release create release pict.exe \ + gh release create release "${assets[@]}" \ --repo "$REPOSITORY" \ --target "$SOURCE_TAG" \ --title "Latest release" \ From 35ccba83c970bd6df08f82e72cfe0d65fcf5acfa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 16 May 2026 17:36:54 +0000 Subject: [PATCH 4/4] Publish platform-scoped release alias assets --- .github/workflows/release-download-alias.yml | 68 +++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-download-alias.yml b/.github/workflows/release-download-alias.yml index 29703e1..cf4f8dc 100644 --- a/.github/workflows/release-download-alias.yml +++ b/.github/workflows/release-download-alias.yml @@ -23,11 +23,13 @@ jobs: steps: - name: Download release assets from source release run: | + set -euo pipefail mkdir -p release-assets gh release download "$SOURCE_TAG" --repo "$REPOSITORY" --pattern "*" --dir release-assets --clobber - name: Recreate rolling release alias run: | + set -euo pipefail shopt -s nullglob assets=(release-assets/*) if [ ${#assets[@]} -eq 0 ]; then @@ -35,12 +37,74 @@ jobs: exit 1 fi + find_asset() { + local platform="$1" + local f name + for f in release-assets/*; do + name=$(basename "$f") + name=${name,,} + case "$platform" in + windows-x64) + [[ "$name" == *win* && "$name" != *arm* && ( "$name" == *x64* || "$name" == *amd64* || "$name" == *x86_64* ) ]] && { echo "$f"; return 0; } + ;; + windows-arm) + [[ "$name" == *win* && ( "$name" == *arm* || "$name" == *aarch64* ) ]] && { echo "$f"; return 0; } + ;; + macos) + [[ ( "$name" == *macos* || "$name" == *darwin* || "$name" == *osx* ) && ( "$name" == *arm* || "$name" == *aarch64* || "$name" == *apple* ) ]] && { echo "$f"; return 0; } + ;; + linux-x64) + [[ "$name" == *linux* && "$name" != *arm* && ( "$name" == *x64* || "$name" == *amd64* || "$name" == *x86_64* ) ]] && { echo "$f"; return 0; } + ;; + linux-arm) + [[ "$name" == *linux* && ( "$name" == *arm* || "$name" == *aarch64* ) ]] && { echo "$f"; return 0; } + ;; + esac + done + return 1 + } + + win_x64_asset="$(find_asset windows-x64 || true)" + win_arm_asset="$(find_asset windows-arm || true)" + macos_asset="$(find_asset macos || true)" + linux_x64_asset="$(find_asset linux-x64 || true)" + linux_arm_asset="$(find_asset linux-arm || true)" + + if [ -z "$win_x64_asset" ] || [ -z "$win_arm_asset" ] || [ -z "$macos_asset" ] || [ -z "$linux_x64_asset" ] || [ -z "$linux_arm_asset" ]; then + echo "Unable to map all required platform assets from release $SOURCE_TAG." + echo "Found files:" + printf ' - %s\n' "${assets[@]}" + exit 1 + fi + if gh release view release --repo "$REPOSITORY" >/dev/null 2>&1; then gh release delete release --repo "$REPOSITORY" --yes --cleanup-tag fi - gh release create release "${assets[@]}" \ + gh release create release \ --repo "$REPOSITORY" \ --target "$SOURCE_TAG" \ --title "Latest release" \ - --notes "Rolling release that keeps https://github.com/$REPOSITORY/releases/download/release/pict.exe pointed at the newest published binary." + --notes "Rolling release that keeps platform-scoped download aliases in sync with the newest published binaries." + + upload_url="$(gh api "repos/$REPOSITORY/releases/tags/release" --jq .upload_url)" + upload_url="${upload_url%\{*}" + + upload_asset() { + local src="$1" + local alias_name="$2" + local encoded_name + encoded_name="$(jq -rn --arg v "$alias_name" '$v|@uri')" + curl --fail-with-body --silent --show-error \ + -X POST \ + -H "Authorization: Bearer $GH_TOKEN" \ + -H "Content-Type: application/octet-stream" \ + --data-binary @"$src" \ + "$upload_url?name=$encoded_name" >/dev/null + } + + upload_asset "$win_x64_asset" "windows-x64/pict.exe" + upload_asset "$win_arm_asset" "windows-arm/pict.exe" + upload_asset "$macos_asset" "macos/pict.exe" + upload_asset "$linux_x64_asset" "linux-x64/pict.exe" + upload_asset "$linux_arm_asset" "linux-arm/pict.exe"