From 8283caaa3470c2df1e667e6b3946f7dab4a4948d Mon Sep 17 00:00:00 2001 From: yash-zededa Date: Mon, 7 Oct 2024 13:46:24 +0200 Subject: [PATCH 1/5] fix: update lts-release.sh to create the lts tag from the latest rc tag feat: Add scripts and Makefile targets for RC and LTS releases In accordance with the testing team's requirement to create a release candidate (RC) before releasing the LTS version of Eve for certification. These scripts automate the creation of RC and LTS releases by calculating the version number based on the latest tag and incrementing it accordingly. Signed-off-by: yash-zededa (cherry picked from commit b20a9db0957accfc20390b98144e898c474c4517) (cherry picked from commit 7649d23d50f02a304fd6e9f3ba30f4a86faf767a) --- .github/workflows/assets.yml | 4 +- .github/workflows/publish.yml | 3 +- Makefile | 24 ++++------ tools/lts-release.sh | 87 ++++++++++++++++++++++++++++++++++ tools/rc-release.sh | 89 +++++++++++++++++++++++++++++++++++ 5 files changed, 189 insertions(+), 18 deletions(-) create mode 100755 tools/lts-release.sh create mode 100755 tools/rc-release.sh diff --git a/.github/workflows/assets.yml b/.github/workflows/assets.yml index 8237c98802..b7fb069967 100644 --- a/.github/workflows/assets.yml +++ b/.github/workflows/assets.yml @@ -47,8 +47,8 @@ jobs: # if the default server is responding -- we can skip apt update $APT_INSTALL || { sudo apt update && $APT_INSTALL ; } echo "ARCH=${{ matrix.arch }}" >> "$GITHUB_ENV" - echo "TAG=$(git describe --always --tags | grep -E '[0-9]*\.[0-9]*\.[0-9]*' || echo snapshot)" >> "$GITHUB_ENV" - - name: ensure clean assets dir + echo "TAG=$(git describe --always --tags | grep -E '[0-9]+\.[0-9]+\.[0-9]' || echo snapshot)" >> "$GITHUB_ENV" + - name: ensure clean assets directory run: | rm -rf assets && mkdir -p assets - name: Pull the EVE release from DockerHUB or build it diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d03feb2dab..0ead9e26d0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -7,8 +7,7 @@ on: # yamllint disable-line rule:truthy - "[0-9]+.[0-9]+" - "[0-9]+.[0-9]+-stable" tags: - - "[0-9]+.[0-9]+.[0-9]+" - - "[0-9]+.[0-9]+.[0-9]+-lts" + - "[0-9]+\\.[0-9]+\\.[0-9]+" jobs: packages: diff --git a/Makefile b/Makefile index 8d05e2c74e..93402ddf4b 100644 --- a/Makefile +++ b/Makefile @@ -827,20 +827,11 @@ proto-vendor: .PHONY: proto-api-% -check-patch-%: - @if ! echo $* | grep -Eq '^[0-9]+\.[0-9]+$$'; then echo "ERROR: must be on a release branch X.Y"; exit 1; fi - @if ! echo $(EVE_TREE_TAG) | grep -Eq '^$*.[0-9]+-'; then echo "ERROR: can't find previous release's tag X.Y.Z"; exit 1; fi +rc-release: + ./tools/rc-release.sh -patch-%: check-patch-% - @$(eval PATCH_TAG:=$*.$(shell echo $$((`echo $(EVE_TREE_TAG) | sed -e 's#-.*$$##' | cut -f3 -d.` + 1)))) - -patch-%-stable: patch-% - @$(eval PATCH_TAG:=$(PATCH_TAG)-lts) - -patch: patch-$(REPO_BRANCH) - @git tag -a -m"Release $(PATCH_TAG)" $(PATCH_TAG) - @echo "Done tagging $(PATCH_TAG) patch release. Check the branch with git log and then run" - @echo " git push origin $(REPO_BRANCH) $(PATCH_TAG)" +lts-release: + ./tools/lts-release.sh release: @bail() { echo "ERROR: $$@" ; exit 1 ; } ;\ @@ -997,7 +988,12 @@ help: @echo " test run EVE tests" @echo " clean clean build artifacts in a current directory (doesn't clean Docker)" @echo " release prepare branch for a release (VERSION=x.y.z required)" - @echo " patch make a patch release on a current branch (must be a release branch)" + @echo " rc-release make a rc release on a current branch (must be a release branch)" + @echo " If the latest lts tag is 14.4.0 then running make rc-release will" + @echo " create 14.4.0-rc1 tag and if the latest tag is 14.4.1-lts then" + @echo " lts-release make a lts release on a current branch (must be a release branch)" + @echo " If the latest lts tag is 14.4.0-lts then running make lts-release + @echo " will create a new lts release 14.4.1-lts" @echo " proto generates Go and Python source from protobuf API definitions" @echo " proto-vendor update vendored API in packages that require it (e.g. pkg/pillar)" @echo " shell drop into docker container setup for Go development" diff --git a/tools/lts-release.sh b/tools/lts-release.sh new file mode 100755 index 0000000000..4979e80806 --- /dev/null +++ b/tools/lts-release.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +# +# Copyright (c) 2024 Zededa, Inc. +# SPDX-License-Identifier: Apache-2.0 +# + +# Get the current branch +git_branch=$(git rev-parse --abbrev-ref HEAD | tr / _) + +# Get the latest tag from the specified branch +latest_tag=$(git describe --tags --abbrev=0 "$git_branch") + +echo "Latest tag: $latest_tag" + +# Check if the input is a valid release branch in the format X.Y (e.g., 1.2) +check_release_branch() { + if ! echo "${git_branch}" | grep -Eq "^[0-9]+\.[0-9]+(-[a-zA-Z]+)?$"; then + echo "ERROR: must be on a release branch X.Y" + exit 1 + fi +} + +# Validate if the latest tag is a valid release tag (e.g., X.Y.Z or X.Y.Z-) +check_tag() { + if ! echo "${latest_tag}" | grep -Eq "^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$"; then + echo "ERROR: can't find previous release's tag X.Y.Z" + exit 1 + fi +} + +# Function to check if the latest tag is an RC tag +is_rc_tag() { + if echo "${latest_tag}" | grep -Eq "^[0-9]+\.[0-9]+\.[0-9]+-rc[0-9]+$"; then + return 0 + else + return 1 + fi +} + +# Function to increment the patch version +increment_patch_version() { + local version=$1 + local major minor patch + IFS='.' read -r major minor patch <<< "$version" + patch=$((patch + 1)) + echo "$major.$minor.$patch" +} + +# Perform release branch validation +check_release_branch + +# Perform tag validation +check_tag + +# If the latest tag is an RC tag +if is_rc_tag; then + # Extract the base version (remove the -rc suffix) + base_version="${latest_tag%-rc*}" + new_tag="${base_version}-lts" + echo "Creating LTS tag: $new_tag from the commit of $latest_tag" + # Create the LTS tag from the commit of the RC release + if git tag -a "$new_tag" "$latest_tag" -m "Release $new_tag"; then + echo "Tagged new version: $new_tag" + echo "Now, push the tag to the remote repository using:" + echo "git push origin $git_branch $new_tag" + else + echo "Error: Failed to create the new LTS tag." + exit 1 + fi +else + # If the latest tag is not an RC tag + echo "Latest tag is not an RC tag. Incrementing the patch version." + # Increment the patch version + new_version=$(increment_patch_version "$latest_tag") + new_tag="${new_version}-lts" + echo "Creating LTS tag: $new_tag from the latest non-RC tag" + # Create the LTS tag from the latest non-RC release + if git tag -a "$new_tag" -m "Release $new_tag"; then + echo "Tagged new version: $new_tag" + echo "Now, push the tag to the remote repository using:" + echo "git push origin $git_branch $new_tag" + else + echo "Error: Failed to create the new LTS tag." + exit 1 + fi +fi diff --git a/tools/rc-release.sh b/tools/rc-release.sh new file mode 100755 index 0000000000..042ad8e69a --- /dev/null +++ b/tools/rc-release.sh @@ -0,0 +1,89 @@ +#!/bin/bash + +# +# Copyright (c) 2024 Zededa, Inc. +# SPDX-License-Identifier: Apache-2.0 +# + +# Get the current branch and replace slashes with underscores +git_branch=$(git rev-parse --abbrev-ref HEAD | tr / _) + +# Get the latest tag from the specified branch +latest_tag=$(git describe --tags --abbrev=0 "$git_branch") + +# Check if the input is a valid release branch in the format X.Y (e.g., 1.2) +check_release_branch() { + if ! echo "${git_branch}" | grep -Eq "^[0-9]+\.[0-9]+(-[a-zA-Z]+)?$"; then + echo "ERROR: must be on a release branch X.Y" + exit 1 + fi +} + +# Check if the latest tag follows the format X.Y.Z +check_tag() { + if ! echo "${latest_tag}" | grep -Eq "^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$"; then + echo "ERROR: can't find previous release's tag X.Y.Z" + exit 1 + fi +} + +# Function to increment the numeric part of a version +increment_version() { + local version=$1 + local base=${version%-*} # Get the base version (e.g., 12.0.4 from 12.0.4-lts) + local suffix=${version##*-} # Get the suffix (e.g., lts or rc1) + + if [[ $suffix == "$version" ]]; then + suffix="" # No suffix + fi + + if [[ $suffix == "lts" ]]; then + # If the suffix is lts, increment the base version and add -rc1 + IFS='.' read -r major minor patch <<< "$base" + patch=$((patch + 1)) + echo "$major.$minor.$patch-rc1" + elif [[ $suffix == rc* ]]; then + # If the suffix is rc, increment the rc number + local rc_number=${suffix#rc} # Get the number after rc + rc_number=$((rc_number + 1)) + echo "$base-rc$rc_number" + else + # If no suffix or unknown suffix, start with rc1 + echo "$base-rc1" + fi +} + +# Validate the new tag name +validate_tag_name() { + # Updated regex to match '12.0.5', '12.0.5-lts', '12.0.5-rc1', etc. + if [[ ! "$1" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z]+[0-9]*)?$ ]]; then + echo "ERROR: '$1' is not a valid tag name." + exit 1 + fi +} + +# Check if a tag is fetched +if [[ -z $latest_tag ]]; then + # If no latest tag is found, assume we're starting fresh and create the first rc0 tag + echo "No tags found in the repository. Starting with version 0.0.0-rc0." + new_version="0.0.0-rc0" +else + # Increment the version according to the rules + check_release_branch + check_tag + new_version=$(increment_version "$latest_tag") +fi + +validate_tag_name "$new_version" + +echo "Creating RC release: '${new_version}'" + +# Create a new tag and check if the command succeeds +if ! git tag -a -m "Release ${new_version}" "${new_version}"; then + echo "Error: Failed to create a new tag." + exit 1 +fi + +echo "Tagged new version: $new_version. Please push the tag to the remote repository" + +echo "git push origin $git_branch $new_version" From a76f04f5f8a6ecf544e13332a2f3ee310675c6f9 Mon Sep 17 00:00:00 2001 From: yash-zededa Date: Fri, 18 Oct 2024 22:35:06 +0200 Subject: [PATCH 2/5] fix: update publish.yml to use the correct glob pattern for building tags Github Actions workflow was not building tags correctly. This commit fixes the issue by updating the glob pattern to build tags. Signed-off-by: yash-zededa (cherry picked from commit 395a8da954aea5de80a7c9182f9d5826293dee16) (cherry picked from commit 5d1f2fae27b05c087e2043cb92f70a32ba2529c2) --- .github/workflows/publish.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0ead9e26d0..b09639efdf 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -7,7 +7,9 @@ on: # yamllint disable-line rule:truthy - "[0-9]+.[0-9]+" - "[0-9]+.[0-9]+-stable" tags: - - "[0-9]+\\.[0-9]+\\.[0-9]+" + - "[0-9]+.[0-9]+.[0-9]+" + - "[0-9]+.[0-9]+.[0-9]+-lts" + - "[0-9]+.[0-9]+.[0-9]+-rc[0-9]+" jobs: packages: From bac19630fe8a94901f8320b720318b984179e98c Mon Sep 17 00:00:00 2001 From: yash-zededa Date: Tue, 22 Oct 2024 17:16:57 +0200 Subject: [PATCH 3/5] fix: update regex in Makefile to correctly handle rc and lts tags The regex now supports both rc and lts, in addition to the major.minor.patch version format. Signed-off-by: yash-zededa (cherry picked from commit bdaa4e579e1a21d95f1bfe9ba01a4f53764c01ec) (cherry picked from commit 97e740f18325a89525223190f4d95da25244df82) --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 93402ddf4b..215a8af1bd 100644 --- a/Makefile +++ b/Makefile @@ -87,7 +87,8 @@ endif REPO_BRANCH=$(shell git rev-parse --abbrev-ref HEAD | tr / _) REPO_SHA=$(shell git describe --match '$$^' --abbrev=8 --always --dirty) -REPO_TAG=$(shell git describe --always --tags | grep -E '[0-9]*\.[0-9]*\.[0-9]*' || echo snapshot) +# set this variable to the current tag only if we are building from a tag (annotated or not), otherwise set it to "snapshot", which means rootfs version will be constructed differently +REPO_TAG=$(shell git describe --always --tags | grep -E '^[0-9]+\.[0-9]+\.[0-9]+(-lts|-rc[0-9]+)?$$' || echo snapshot) REPO_DIRTY_TAG=$(if $(findstring -dirty,$(REPO_SHA)),-$(shell date -u +"%Y-%m-%d.%H.%M")) EVE_TREE_TAG = $(shell git describe --abbrev=8 --always --dirty --tags) From 0ca5ceec5d4e25022f08c4a95ddd520f89c94e5b Mon Sep 17 00:00:00 2001 From: yash-zededa Date: Mon, 28 Oct 2024 16:52:03 +0100 Subject: [PATCH 4/5] update: switch assets.yml to use GitHub API for artifact upload Previous action for uploading artifacts to GitHub Releases failed due to parallel (matrix) execution issues. Replaced it with direct GitHub API calls to handle uploads. This change provides more flexibility and control over artifact management and release handling. Added step to generate sha256 checksum for rootfs.img Signed-off-by: yash-zededa (cherry picked from commit e875d32dca80f81db11ec927be49d4ddd536755a) (cherry picked from commit 75340228320cad4cf6ec71ba2aca44c643763d9e) (cherry picked from commit 20d64977c3dae79530687c2274c072d827451e85) --- .github/workflows/assets.yml | 190 +++++++++-------------------------- 1 file changed, 48 insertions(+), 142 deletions(-) diff --git a/.github/workflows/assets.yml b/.github/workflows/assets.yml index b7fb069967..5a6dcd1e3a 100644 --- a/.github/workflows/assets.yml +++ b/.github/workflows/assets.yml @@ -20,6 +20,30 @@ on: # yamllint disable-line rule:truthy type: string jobs: + create_release: + runs-on: ubuntu-latest + outputs: + release_id: ${{ steps.create_release.outputs.release_id }} + upload_url: ${{ steps.create_release.outputs.upload_url }} + steps: + - name: Create GitHub Release + id: create_release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + response=$(curl -s -X POST \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "tag_name": "${{ inputs.tag_ref }}", + "name": "${{ inputs.tag_ref }}", + "draft": false, + "prerelease": true + }' https://api.github.com/repos/${{ github.repository }}/releases) + release_id=$(echo "$response" | jq -r .id) + upload_url=$(echo "$response" | jq -r .upload_url | sed -e "s/{?name,label}//") + echo "release_id=$release_id" >> "$GITHUB_OUTPUT" + echo "upload_url=$upload_url" >> "$GITHUB_OUTPUT" build: runs-on: ubuntu-20.04 strategy: @@ -89,147 +113,29 @@ jobs: docker create --name eve_sources "$EVE_SOURCES" bash docker export --output assets/collected_sources.tar.gz eve_sources docker rm eve_sources - - name: Create a GitHub release and clean up artifacts - id: create-release - uses: actions/github-script@v3 - with: - result-encoding: string - script: | - console.log(context) - tag = '${{ inputs.tag_ref }}' - - // first create a release -- it is OK if that fails, - // since it means the release is already there - try { - const raw = (await github.repos.createRelease({ - owner: context.repo.owner, - repo: context.repo.repo, - tag_name: tag, - name: 'Release ' + tag, - prerelease: true, - })).data - console.log(raw) - } catch (e) {} - - // get the release ID - const release = (await github.repos.getReleaseByTag({ - owner: context.repo.owner, - repo: context.repo.repo, - tag: tag, - })).data - - // get assets for that ID - const assets = (await github.repos.listReleaseAssets({ - owner: context.repo.owner, - repo: context.repo.repo, - release_id: release.id, - })).data - - // remove all assets (since we will be uploading new ones) - // note that we only consider assets coming from the same - // architecture we're running on -- this is because GH - // release assets can only be flat (no folders allowed) - if (Array.isArray(assets) && assets.length > 0) { - for (const asset of assets) { - if (asset.name.startsWith('${{ env.ARCH }}')) { - await github.repos.deleteReleaseAsset({ - owner: context.repo.owner, - repo: context.repo.repo, - asset_id: asset.id, - }) - } - } - } - - return release.upload_url - - - name: Upload rootfs for the release - id: upload-rootfs-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.result }} - asset_path: assets/rootfs.img - asset_name: ${{ env.ARCH }}.rootfs.img - asset_content_type: application/octet-stream - - name: Upload kernel for the release - id: upload-kernel-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.result }} - asset_path: assets/kernel - asset_name: ${{ env.ARCH }}.kernel - asset_content_type: application/octet-stream - - name: Upload installer.img for the release - id: upload-installer-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.result }} - asset_path: assets/installer.img - asset_name: ${{ env.ARCH }}.installer.img - asset_content_type: application/octet-stream - - name: Upload initrd.img for the release - id: upload-initrd-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.result }} - asset_path: assets/initrd.img - asset_name: ${{ env.ARCH }}.initrd.img - asset_content_type: application/octet-stream - - name: Upload initrd.bits for the release - id: upload-initrd-bits-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.result }} - asset_path: assets/initrd.bits - asset_name: ${{ env.ARCH }}.initrd.bits - asset_content_type: application/octet-stream - - name: Upload ipxe.efi for the release - id: upload-ipxe-efi-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.result }} - asset_path: assets/ipxe.efi - asset_name: ${{ env.ARCH }}.ipxe.efi - asset_content_type: application/octet-stream - - name: Upload ipxe.efi.cfg for the release - id: upload-ipxe-efi-cfg-asset - uses: actions/upload-release-asset@v1 + - name: Create SHA256 checksum, rename, and upload files env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.result }} - asset_path: assets/ipxe.efi.cfg - asset_name: ${{ env.ARCH }}.ipxe.efi.cfg - asset_content_type: application/octet-stream - - name: Upload ipxe.efi.ip.cfg for the release - id: upload-ipxe-efi-ip-cfg-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.result }} - asset_path: assets/ipxe.efi.ip.cfg - asset_name: ${{ env.ARCH }}.ipxe.efi.ip.cfg - asset_content_type: application/octet-stream - - name: Upload COLLECTED_SOURCES - id: upload-collected-sources-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.result }} - asset_path: assets/collected_sources.tar.gz - asset_name: ${{ env.ARCH }}.collected_sources.tar.gz - asset_content_type: application/octet-stream + RELEASE_ID: ${{ needs.create_release.outputs.release_id }} + UPLOAD_URL: ${{ needs.create_release.outputs.upload_url }} + run: | + # Create SHA256 checksum for rootfs.img + sha256sum "assets/rootfs.img" | awk '{ print $1 }' > "assets/rootfs.img.sha256" + for file in assets/*; do + base_name=$(basename "$asset") + # Add ARCH prefix + new_name="${ARCH}.${base_name}" + # Rename the file + mv "$asset" "assets/$new_name" + echo "Uploading assets/$new_name as $new_name..." + upload_response=$(curl -s -X POST \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "Content-Type: application/octet-stream" \ + --data-binary @"assets/$new_name" \ + "$UPLOAD_URL?name=$new_name") + if echo "$upload_response" | jq -e .id > /dev/null; then + echo "$file_name uploaded successfully." + else + echo "Error uploading $file_name: $upload_response" + fi + done From f7384b6c246f010087f8967579c68e65a5aaa7aa Mon Sep 17 00:00:00 2001 From: yash-zededa Date: Thu, 31 Oct 2024 16:16:35 +0100 Subject: [PATCH 5/5] fix: assets upload to use the correct variable name. Added needs on for the upload job to get the upload url from the create release job. Signed-off-by: yash-zededa (cherry picked from commit a3fbdd9103f0933b0b8db0620f3b2ce94083e497) (cherry picked from commit 248ab873ce94c9a63519868f1d8135448b8aca31) --- .github/workflows/assets.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/assets.yml b/.github/workflows/assets.yml index 5a6dcd1e3a..b7bc2e742d 100644 --- a/.github/workflows/assets.yml +++ b/.github/workflows/assets.yml @@ -42,10 +42,12 @@ jobs: }' https://api.github.com/repos/${{ github.repository }}/releases) release_id=$(echo "$response" | jq -r .id) upload_url=$(echo "$response" | jq -r .upload_url | sed -e "s/{?name,label}//") + echo $upload_url echo "release_id=$release_id" >> "$GITHUB_OUTPUT" echo "upload_url=$upload_url" >> "$GITHUB_OUTPUT" build: runs-on: ubuntu-20.04 + needs: create_release strategy: fail-fast: false matrix: @@ -122,11 +124,11 @@ jobs: # Create SHA256 checksum for rootfs.img sha256sum "assets/rootfs.img" | awk '{ print $1 }' > "assets/rootfs.img.sha256" for file in assets/*; do - base_name=$(basename "$asset") + base_name=$(basename "$file") # Add ARCH prefix new_name="${ARCH}.${base_name}" # Rename the file - mv "$asset" "assets/$new_name" + mv "$file" "assets/$new_name" echo "Uploading assets/$new_name as $new_name..." upload_response=$(curl -s -X POST \ -H "Authorization: Bearer $GITHUB_TOKEN" \