|
12 | 12 | required: true |
13 | 13 | default: false |
14 | 14 | type: boolean |
| 15 | + reuse_existing_draft_assets: |
| 16 | + description: Promote an existing validated draft without rebuilding platform installers |
| 17 | + required: true |
| 18 | + default: false |
| 19 | + type: boolean |
15 | 20 |
|
16 | 21 | permissions: |
17 | 22 | contents: write |
|
27 | 32 |
|
28 | 33 | jobs: |
29 | 34 | build: |
| 35 | + if: ${{ !inputs.reuse_existing_draft_assets }} |
30 | 36 | runs-on: ubuntu-latest |
31 | 37 | timeout-minutes: 30 |
32 | 38 |
|
@@ -151,6 +157,7 @@ jobs: |
151 | 157 | retention-days: 1 |
152 | 158 |
|
153 | 159 | prepare-runtime: |
| 160 | + if: ${{ !inputs.reuse_existing_draft_assets }} |
154 | 161 | runs-on: ubuntu-latest |
155 | 162 | timeout-minutes: 90 |
156 | 163 |
|
@@ -325,6 +332,7 @@ jobs: |
325 | 332 | exit 1 |
326 | 333 |
|
327 | 334 | prepare-terminal-platform-runtime: |
| 335 | + if: ${{ !inputs.reuse_existing_draft_assets }} |
328 | 336 | runs-on: ubuntu-latest |
329 | 337 | timeout-minutes: 90 |
330 | 338 |
|
@@ -944,207 +952,45 @@ jobs: |
944 | 952 | needs: [release-mac, release-win, release-linux] |
945 | 953 | runs-on: ubuntu-latest |
946 | 954 | timeout-minutes: 30 |
947 | | - if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish_release }} |
| 955 | + if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish_release && !inputs.reuse_existing_draft_assets }} |
948 | 956 |
|
949 | 957 | steps: |
950 | | - - name: Checkout release guard |
| 958 | + - name: Checkout release promotion |
951 | 959 | uses: actions/checkout@v6 |
952 | 960 | with: |
953 | 961 | persist-credentials: false |
954 | 962 |
|
955 | | - - name: Upload stable download aliases |
956 | | - env: |
957 | | - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
958 | | - run: | |
959 | | - set -euo pipefail |
960 | | - VERSION="${RELEASE_TAG#v}" |
961 | | - TAG="${RELEASE_TAG}" |
962 | | - REPO="${GITHUB_REPOSITORY}" |
963 | | - TMP_DIR="$(mktemp -d)" |
964 | | - trap 'rm -rf "$TMP_DIR"' EXIT |
965 | | -
|
966 | | - declare -A STABLE_ALIASES=( |
967 | | - ["Agent.Teams.AI-arm64.dmg"]="Agent.Teams.AI-${VERSION}-arm64.dmg" |
968 | | - ["Agent.Teams.AI-x64.dmg"]="Agent.Teams.AI-${VERSION}-x64.dmg" |
969 | | - ["Agent.Teams.AI.Setup.exe"]="Agent.Teams.AI.Setup.${VERSION}.exe" |
970 | | - ["Agent.Teams.AI.AppImage"]="Agent.Teams.AI-${VERSION}.AppImage" |
971 | | - ["agent-teams-ai-amd64.deb"]="agent-teams-ai_${VERSION}_amd64.deb" |
972 | | - ["agent-teams-ai-x86_64.rpm"]="agent-teams-ai-${VERSION}.x86_64.rpm" |
973 | | - ["agent-teams-ai.pacman"]="agent-teams-ai-${VERSION}.pacman" |
974 | | - ) |
975 | | -
|
976 | | - declare -A LEGACY_STABLE_ALIASES=( |
977 | | - ["Claude-Agent-Teams-UI-arm64.dmg"]="Agent.Teams.AI-${VERSION}-arm64.dmg" |
978 | | - ["Claude-Agent-Teams-UI-x64.dmg"]="Agent.Teams.AI-${VERSION}-x64.dmg" |
979 | | - ["Claude-Agent-Teams-UI-Setup.exe"]="Agent.Teams.AI.Setup.${VERSION}.exe" |
980 | | - ["Claude-Agent-Teams-UI.AppImage"]="Agent.Teams.AI-${VERSION}.AppImage" |
981 | | - ["Claude-Agent-Teams-UI-amd64.deb"]="agent-teams-ai_${VERSION}_amd64.deb" |
982 | | - ["Claude-Agent-Teams-UI-x86_64.rpm"]="agent-teams-ai-${VERSION}.x86_64.rpm" |
983 | | - ["Claude-Agent-Teams-UI.pacman"]="agent-teams-ai-${VERSION}.pacman" |
984 | | - ) |
985 | | -
|
986 | | - declare -A LEGACY_UPDATER_ALIASES=( |
987 | | - ["Claude.Agent.Teams.UI-${VERSION}-arm64-mac.zip"]="Agent.Teams.AI-${VERSION}-arm64-mac.zip" |
988 | | - ["Claude.Agent.Teams.UI-${VERSION}-arm64.dmg"]="Agent.Teams.AI-${VERSION}-arm64.dmg" |
989 | | - ["Claude.Agent.Teams.UI-${VERSION}-mac.zip"]="Agent.Teams.AI-${VERSION}-x64-mac.zip" |
990 | | - ["Claude.Agent.Teams.UI-${VERSION}.dmg"]="Agent.Teams.AI-${VERSION}-x64.dmg" |
991 | | - ["Claude.Agent.Teams.UI.Setup.${VERSION}.exe"]="Agent.Teams.AI.Setup.${VERSION}.exe" |
992 | | - ["Claude.Agent.Teams.UI-${VERSION}.AppImage"]="Agent.Teams.AI-${VERSION}.AppImage" |
993 | | - ) |
994 | | -
|
995 | | - upload_aliases() { |
996 | | - local label="$1" |
997 | | - local -n aliases="$2" |
998 | | -
|
999 | | - for ALIAS_NAME in "${!aliases[@]}"; do |
1000 | | - VERSIONED_NAME="${aliases[$ALIAS_NAME]}" |
1001 | | - echo "Uploading ${label} alias: ${ALIAS_NAME} -> ${VERSIONED_NAME}" |
1002 | | - download_once "${VERSIONED_NAME}" |
1003 | | - cp "${TMP_DIR}/${VERSIONED_NAME}" "${TMP_DIR}/${ALIAS_NAME}" |
1004 | | - upload_release_asset "${TMP_DIR}/${ALIAS_NAME}" |
1005 | | - done |
1006 | | - } |
1007 | | -
|
1008 | | - upload_release_asset() { |
1009 | | - local path="$1" |
1010 | | - timeout 300s gh release upload "${TAG}" "${path}" --repo "$REPO" --clobber || { |
1011 | | - echo "Retrying upload for ${path}" |
1012 | | - sleep 5 |
1013 | | - timeout 300s gh release upload "${TAG}" "${path}" --repo "$REPO" --clobber |
1014 | | - } |
1015 | | - } |
1016 | | -
|
1017 | | - download_once() { |
1018 | | - local name="$1" |
1019 | | - if [[ -f "${TMP_DIR}/${name}" ]]; then |
1020 | | - return |
1021 | | - fi |
1022 | | - gh release download "${TAG}" \ |
1023 | | - --repo "$REPO" \ |
1024 | | - --pattern "${name}" \ |
1025 | | - --dir "$TMP_DIR" \ |
1026 | | - --clobber |
1027 | | - } |
1028 | | -
|
1029 | | - upload_aliases "stable" STABLE_ALIASES |
1030 | | - upload_aliases "legacy stable" LEGACY_STABLE_ALIASES |
1031 | | - upload_aliases "legacy updater" LEGACY_UPDATER_ALIASES |
1032 | | -
|
1033 | | - - name: Publish canonical updater metadata |
1034 | | - env: |
1035 | | - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
1036 | | - run: | |
1037 | | - set -euo pipefail |
1038 | | - VERSION="${RELEASE_TAG#v}" |
1039 | | - TAG="${RELEASE_TAG}" |
1040 | | - REPO="${GITHUB_REPOSITORY}" |
1041 | | - RELEASE_DATE="$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")" |
1042 | | - TMP_DIR="$(mktemp -d)" |
1043 | | - cd "$TMP_DIR" |
1044 | | -
|
1045 | | - sha512_base64() { |
1046 | | - openssl dgst -sha512 -binary "$1" | openssl base64 -A |
1047 | | - } |
1048 | | -
|
1049 | | - file_size() { |
1050 | | - wc -c < "$1" | tr -d '[:space:]' |
1051 | | - } |
1052 | | -
|
1053 | | - download_asset() { |
1054 | | - local name="$1" |
1055 | | - gh release download "${TAG}" \ |
1056 | | - --repo "${REPO}" \ |
1057 | | - --pattern "$name" \ |
1058 | | - --dir . \ |
1059 | | - --clobber |
1060 | | - } |
1061 | | -
|
1062 | | - # Canonical Windows feed |
1063 | | - WIN_ASSET="Agent.Teams.AI.Setup.${VERSION}.exe" |
1064 | | - download_asset "${WIN_ASSET}" |
1065 | | - WIN_SHA="$(sha512_base64 "${WIN_ASSET}")" |
1066 | | - WIN_SIZE="$(file_size "${WIN_ASSET}")" |
1067 | | - cat > latest.yml <<EOF |
1068 | | - version: ${VERSION} |
1069 | | - files: |
1070 | | - - url: ${WIN_ASSET} |
1071 | | - sha512: ${WIN_SHA} |
1072 | | - size: ${WIN_SIZE} |
1073 | | - path: ${WIN_ASSET} |
1074 | | - sha512: ${WIN_SHA} |
1075 | | - releaseDate: '${RELEASE_DATE}' |
1076 | | - EOF |
1077 | | -
|
1078 | | - # Canonical Linux feed |
1079 | | - LINUX_ASSET="Agent.Teams.AI-${VERSION}.AppImage" |
1080 | | - download_asset "${LINUX_ASSET}" |
1081 | | - LINUX_SHA="$(sha512_base64 "${LINUX_ASSET}")" |
1082 | | - LINUX_SIZE="$(file_size "${LINUX_ASSET}")" |
1083 | | - cat > latest-linux.yml <<EOF |
1084 | | - version: ${VERSION} |
1085 | | - files: |
1086 | | - - url: ${LINUX_ASSET} |
1087 | | - sha512: ${LINUX_SHA} |
1088 | | - size: ${LINUX_SIZE} |
1089 | | - path: ${LINUX_ASSET} |
1090 | | - sha512: ${LINUX_SHA} |
1091 | | - releaseDate: '${RELEASE_DATE}' |
1092 | | - EOF |
1093 | | -
|
1094 | | - # Canonical macOS feed. |
1095 | | - # Include both architectures so legacy Intel builds can see the |
1096 | | - # update without downloading the Apple Silicon zip. |
1097 | | - download_asset "Agent.Teams.AI-${VERSION}-arm64-mac.zip" |
1098 | | - download_asset "Agent.Teams.AI-${VERSION}-arm64.dmg" |
1099 | | - download_asset "Agent.Teams.AI-${VERSION}-x64-mac.zip" |
1100 | | - download_asset "Agent.Teams.AI-${VERSION}-x64.dmg" |
1101 | | - MAC_ARM64_ZIP_SHA="$(sha512_base64 "Agent.Teams.AI-${VERSION}-arm64-mac.zip")" |
1102 | | - MAC_ARM64_ZIP_SIZE="$(file_size "Agent.Teams.AI-${VERSION}-arm64-mac.zip")" |
1103 | | - MAC_ARM64_DMG_SHA="$(sha512_base64 "Agent.Teams.AI-${VERSION}-arm64.dmg")" |
1104 | | - MAC_ARM64_DMG_SIZE="$(file_size "Agent.Teams.AI-${VERSION}-arm64.dmg")" |
1105 | | - MAC_X64_ZIP_SHA="$(sha512_base64 "Agent.Teams.AI-${VERSION}-x64-mac.zip")" |
1106 | | - MAC_X64_ZIP_SIZE="$(file_size "Agent.Teams.AI-${VERSION}-x64-mac.zip")" |
1107 | | - MAC_X64_DMG_SHA="$(sha512_base64 "Agent.Teams.AI-${VERSION}-x64.dmg")" |
1108 | | - MAC_X64_DMG_SIZE="$(file_size "Agent.Teams.AI-${VERSION}-x64.dmg")" |
1109 | | - cat > latest-mac.yml <<EOF |
1110 | | - version: ${VERSION} |
1111 | | - files: |
1112 | | - - url: Agent.Teams.AI-${VERSION}-arm64-mac.zip |
1113 | | - sha512: ${MAC_ARM64_ZIP_SHA} |
1114 | | - size: ${MAC_ARM64_ZIP_SIZE} |
1115 | | - - url: Agent.Teams.AI-${VERSION}-arm64.dmg |
1116 | | - sha512: ${MAC_ARM64_DMG_SHA} |
1117 | | - size: ${MAC_ARM64_DMG_SIZE} |
1118 | | - - url: Agent.Teams.AI-${VERSION}-x64-mac.zip |
1119 | | - sha512: ${MAC_X64_ZIP_SHA} |
1120 | | - size: ${MAC_X64_ZIP_SIZE} |
1121 | | - - url: Agent.Teams.AI-${VERSION}-x64.dmg |
1122 | | - sha512: ${MAC_X64_DMG_SHA} |
1123 | | - size: ${MAC_X64_DMG_SIZE} |
1124 | | - path: Agent.Teams.AI-${VERSION}-arm64-mac.zip |
1125 | | - sha512: ${MAC_ARM64_ZIP_SHA} |
1126 | | - releaseDate: '${RELEASE_DATE}' |
1127 | | - EOF |
1128 | | -
|
1129 | | - gh release upload "${TAG}" latest.yml latest-linux.yml latest-mac.yml --repo "${REPO}" --clobber |
1130 | | -
|
1131 | | - - name: Publish release |
1132 | | - if: ${{ inputs.publish_release }} |
| 963 | + - name: Promote validated release assets |
1133 | 964 | env: |
1134 | 965 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 966 | + RELEASE_REPOSITORY: ${{ github.repository }} |
| 967 | + PUBLISH_RELEASE: 'true' |
| 968 | + ALLOW_PUBLISHED_RELEASE_RECOVERY: 'true' |
| 969 | + REDRAFT_INCOMPLETE_RELEASE: 'true' |
| 970 | + run: node scripts/ci/promote-existing-draft.mjs |
| 971 | + |
| 972 | + promote-existing-draft: |
| 973 | + runs-on: ubuntu-latest |
| 974 | + timeout-minutes: 30 |
| 975 | + if: ${{ github.event_name == 'workflow_dispatch' && inputs.reuse_existing_draft_assets }} |
| 976 | + |
| 977 | + steps: |
| 978 | + - name: Checkout release promotion |
| 979 | + uses: actions/checkout@v6 |
| 980 | + with: |
| 981 | + persist-credentials: false |
| 982 | + |
| 983 | + - name: Require publication mode |
| 984 | + if: ${{ !inputs.publish_release }} |
1135 | 985 | run: | |
1136 | | - set -euo pipefail |
1137 | | - TAG="${RELEASE_TAG}" |
1138 | | - gh release edit "${TAG}" --repo "${GITHUB_REPOSITORY}" --draft=false --latest |
| 986 | + echo "reuse_existing_draft_assets requires publish_release=true" >&2 |
| 987 | + exit 1 |
1139 | 988 |
|
1140 | | - - name: Verify published updater channel |
| 989 | + - name: Promote existing validated draft |
1141 | 990 | if: ${{ inputs.publish_release }} |
1142 | 991 | env: |
1143 | 992 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
1144 | 993 | RELEASE_REPOSITORY: ${{ github.repository }} |
| 994 | + PUBLISH_RELEASE: 'true' |
1145 | 995 | REDRAFT_INCOMPLETE_RELEASE: 'true' |
1146 | | - run: bash scripts/ci/verify-published-updater-release.sh |
1147 | | - |
1148 | | - - name: Keep release as draft |
1149 | | - if: ${{ github.event_name == 'workflow_dispatch' && !inputs.publish_release }} |
1150 | | - run: echo "Draft release ${RELEASE_TAG} is ready. It was not published because publish_release=false." |
| 996 | + run: node scripts/ci/promote-existing-draft.mjs |
0 commit comments