Compare commits

...

3 Commits

Author SHA1 Message Date
Claude Bot
c66c1ca842 Fix release workflow order: create tar archives before signing
- Move tar-archives job to run before sign job
- Sign job now includes tar archives in SHA256 signature
- Add retry logic for zip files not immediately available
- Maintains proper dependency chain: tar-archives → sign → other jobs

This ensures the SHASUMS256.txt file includes hashes for both
zip files and the new tar.gz/tar.xz archives.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-11 13:48:59 +00:00
Claude Bot
7bae016943 Add DRY_RUN flag to tar archive script for testing
- Added DRY_RUN environment variable to skip uploads
- Updated documentation with environment variable usage
- Preserves temporary directory when DRY_RUN=1 for inspection
- Allows testing archive creation without GitHub API calls

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-11 13:43:42 +00:00
Claude Bot
7092282549 Add tar.gz and tar.xz archive generation to releases
- Created shell script to download, extract, and repackage zip files as tar archives
- Added GitHub Actions job to generate tar archives after signing
- Maintains identical directory structure as zip files
- Archives are uploaded to the same GitHub release

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-11 13:38:45 +00:00
2 changed files with 212 additions and 0 deletions

View File

@@ -53,6 +53,7 @@ jobs:
sign:
name: Sign Release
runs-on: ubuntu-latest
needs: tar-archives
if: ${{ github.repository_owner == 'oven-sh' }}
permissions:
contents: write
@@ -79,6 +80,24 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
tar-archives:
name: Create tar.gz and tar.xz archives
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'oven-sh' }}
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y curl jq unzip tar xz-utils
- name: Create and upload tar archives
run: |
./scripts/create-tar-archives.sh "${{ env.BUN_VERSION }}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
npm:
name: Release to NPM
runs-on: ubuntu-latest

193
scripts/create-tar-archives.sh Executable file
View File

@@ -0,0 +1,193 @@
#!/bin/bash
# Script to download zip files from a GitHub release, extract them, and create tar.gz and tar.xz archives
# Usage: ./create-tar-archives.sh <tag> [temp_dir]
#
# Environment variables:
# GITHUB_TOKEN - If set, archives will be uploaded to the GitHub release
# DRY_RUN - If set to "1", skips uploading (useful for testing)
set -euo pipefail
TAG="${1:-}"
TEMP_DIR="${2:-/tmp/bun-archives-$$}"
GITHUB_REPO="oven-sh/bun"
if [[ -z "$TAG" ]]; then
echo "Usage: $0 <tag> [temp_dir]"
echo "Example: $0 bun-v1.2.20"
exit 1
fi
# Ensure we have required tools
for tool in curl jq unzip tar; do
if ! command -v "$tool" &> /dev/null; then
echo "Error: $tool is not installed"
exit 1
fi
done
echo "Creating temporary directory: $TEMP_DIR"
mkdir -p "$TEMP_DIR"
# Function to cleanup on exit
cleanup() {
if [[ -d "$TEMP_DIR" ]]; then
echo "Cleaning up temporary directory: $TEMP_DIR"
rm -rf "$TEMP_DIR"
fi
}
trap cleanup EXIT
echo "Fetching release information for tag: $TAG"
RELEASE_DATA=$(curl -s "https://api.github.com/repos/$GITHUB_REPO/releases/tags/$TAG")
if [[ $(echo "$RELEASE_DATA" | jq -r '.message // empty') == "Not Found" ]]; then
echo "Error: Release with tag '$TAG' not found"
exit 1
fi
# Get all zip file URLs
ZIP_ASSETS=$(echo "$RELEASE_DATA" | jq -r '.assets[] | select(.name | endswith(".zip")) | "\(.name)|\(.browser_download_url)"')
if [[ -z "$ZIP_ASSETS" ]]; then
echo "No zip files found in release $TAG"
# If this is a manual or scheduled run, wait a bit and retry once
# in case zip files are still being uploaded
if [[ "${GITHUB_EVENT_NAME:-}" == "workflow_dispatch" || "${GITHUB_EVENT_NAME:-}" == "schedule" ]]; then
echo "Waiting 30 seconds and retrying once..."
sleep 30
RELEASE_DATA=$(curl -s "https://api.github.com/repos/$GITHUB_REPO/releases/tags/$TAG")
ZIP_ASSETS=$(echo "$RELEASE_DATA" | jq -r '.assets[] | select(.name | endswith(".zip")) | "\(.name)|\(.browser_download_url)"')
if [[ -z "$ZIP_ASSETS" ]]; then
echo "Still no zip files found after retry"
exit 0
else
echo "Found zip files after retry"
fi
else
exit 0
fi
fi
echo "Found zip files to process:"
echo "$ZIP_ASSETS" | cut -d'|' -f1 | sed 's/^/ - /'
CREATED_ARCHIVES=()
while IFS='|' read -r ASSET_NAME DOWNLOAD_URL; do
echo
echo "Processing: $ASSET_NAME"
# Download the zip file
ZIP_PATH="$TEMP_DIR/$ASSET_NAME"
echo " Downloading $ASSET_NAME..."
curl -L -o "$ZIP_PATH" "$DOWNLOAD_URL"
# Extract the zip file
EXTRACT_DIR="$TEMP_DIR/extract_$(basename "$ASSET_NAME" .zip)"
mkdir -p "$EXTRACT_DIR"
echo " Extracting to $EXTRACT_DIR..."
unzip -q "$ZIP_PATH" -d "$EXTRACT_DIR"
# Find the directory inside (should be only one)
CONTENT_DIR=$(find "$EXTRACT_DIR" -mindepth 1 -maxdepth 1 -type d | head -1)
if [[ -z "$CONTENT_DIR" ]]; then
echo " Warning: No directory found inside $ASSET_NAME, skipping..."
continue
fi
CONTENT_DIR_NAME=$(basename "$CONTENT_DIR")
echo " Found content directory: $CONTENT_DIR_NAME"
# Create tar.gz archive
TAR_GZ_NAME="${ASSET_NAME%.zip}.tar.gz"
TAR_GZ_PATH="$TEMP_DIR/$TAR_GZ_NAME"
echo " Creating $TAR_GZ_NAME..."
(cd "$EXTRACT_DIR" && tar -czf "$TAR_GZ_PATH" "$CONTENT_DIR_NAME")
CREATED_ARCHIVES+=("$TAR_GZ_PATH")
# Create tar.xz archive
TAR_XZ_NAME="${ASSET_NAME%.zip}.tar.xz"
TAR_XZ_PATH="$TEMP_DIR/$TAR_XZ_NAME"
echo " Creating $TAR_XZ_NAME..."
(cd "$EXTRACT_DIR" && tar -cJf "$TAR_XZ_PATH" "$CONTENT_DIR_NAME")
CREATED_ARCHIVES+=("$TAR_XZ_PATH")
# Clean up intermediate files
rm -f "$ZIP_PATH"
rm -rf "$EXTRACT_DIR"
done <<< "$ZIP_ASSETS"
echo
echo "Created archives:"
for archive in "${CREATED_ARCHIVES[@]}"; do
echo " - $(basename "$archive") ($(du -h "$archive" | cut -f1))"
done
# If GITHUB_TOKEN is set and DRY_RUN is not enabled, upload the archives to the release
if [[ -n "${GITHUB_TOKEN:-}" && "${DRY_RUN:-0}" != "1" ]]; then
echo
echo "GITHUB_TOKEN found, uploading archives to release..."
RELEASE_ID=$(echo "$RELEASE_DATA" | jq -r '.id')
UPLOAD_URL="https://uploads.github.com/repos/$GITHUB_REPO/releases/$RELEASE_ID/assets"
for ARCHIVE_PATH in "${CREATED_ARCHIVES[@]}"; do
ARCHIVE_NAME=$(basename "$ARCHIVE_PATH")
echo " Uploading $ARCHIVE_NAME..."
# Delete existing asset if it exists
EXISTING_ASSET_ID=$(echo "$RELEASE_DATA" | jq -r ".assets[] | select(.name == \"$ARCHIVE_NAME\") | .id")
if [[ "$EXISTING_ASSET_ID" != "null" && -n "$EXISTING_ASSET_ID" ]]; then
echo " Deleting existing asset..."
curl -X DELETE \
-H "Authorization: token $GITHUB_TOKEN" \
"https://api.github.com/repos/$GITHUB_REPO/releases/assets/$EXISTING_ASSET_ID"
fi
# Upload new asset
CONTENT_TYPE="application/octet-stream"
if [[ "$ARCHIVE_NAME" == *.tar.gz ]]; then
CONTENT_TYPE="application/gzip"
elif [[ "$ARCHIVE_NAME" == *.tar.xz ]]; then
CONTENT_TYPE="application/x-xz"
fi
curl -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Content-Type: $CONTENT_TYPE" \
--data-binary "@$ARCHIVE_PATH" \
"$UPLOAD_URL?name=$ARCHIVE_NAME"
echo " Uploaded $ARCHIVE_NAME"
done
elif [[ "${DRY_RUN:-0}" == "1" ]]; then
echo
echo "DRY_RUN=1: Skipping upload. Archives saved to:"
for archive in "${CREATED_ARCHIVES[@]}"; do
echo " $archive"
done
echo
echo "To upload these, set GITHUB_TOKEN and run without DRY_RUN=1"
else
echo
echo "GITHUB_TOKEN not set, archives saved to:"
for archive in "${CREATED_ARCHIVES[@]}"; do
echo " $archive"
done
echo
echo "To upload these manually, set GITHUB_TOKEN and re-run this script."
fi
# Don't cleanup if GITHUB_TOKEN is not set or DRY_RUN=1, so user can access the files
if [[ -z "${GITHUB_TOKEN:-}" || "${DRY_RUN:-0}" == "1" ]]; then
trap '' EXIT # Disable cleanup
echo "Temporary directory preserved: $TEMP_DIR"
fi
echo
echo "Done!"