Skip to content

🚀 Release Builder #9

🚀 Release Builder

🚀 Release Builder #9

# This workflow will build the project and create a release on demand
# Uses:
# OS: ubuntu-latest
# Go: go 1.x
name: 🚀 Release Builder
on:
schedule:
# Runs every Friday at 12:00 PM IST (6:30 AM UTC)
- cron: '30 6 * * 5'
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g., v1.0.0). Leave empty to use version.txt'
required: false
type: string
prerelease:
description: 'Set as a pre-release'
required: false
type: boolean
default: true
run_performance_test:
description: 'Run performance tests after release'
required: false
type: boolean
default: true
# Add permissions to allow pushing tags and packages
permissions:
contents: write
packages: write
env:
GOFLAGS: "-mod=readonly"
jobs:
build-thunder:
name: ⚡ Build Thunder
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get_version.outputs.version }}
prerelease: ${{ steps.get_version.outputs.prerelease }}
run_performance_test: ${{ steps.get_version.outputs.run_performance_test }}
steps:
- name: 📥 Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 📝 Determine Release Version
id: get_version
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ] && [ -n "${{ github.event.inputs.version }}" ]; then
# Use manually provided version
VERSION="${{ github.event.inputs.version }}"
PRERELEASE="${{ github.event.inputs.prerelease }}"
RUN_PERF_TEST="${{ github.event.inputs.run_performance_test }}"
else
# Scheduled run or manual run without version - read from version.txt
if [ ! -f version.txt ] || [ -z "$(cat version.txt | tr -d '[:space:]')" ]; then
echo "❌ Error: version.txt not found or empty"
exit 1
fi
VERSION=$(tr -d '[:space:]' < version.txt)
PRERELEASE="true"
RUN_PERF_TEST="true"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "prerelease=$PRERELEASE" >> $GITHUB_OUTPUT
echo "run_performance_test=$RUN_PERF_TEST" >> $GITHUB_OUTPUT
echo "✅ Using version: $VERSION"
- name: ✅ Validate Release Version
run: |
VERSION="${{ steps.get_version.outputs.version }}"
# Check version format
if ! [[ $VERSION =~ ^v[0-9]+\.[0-9]+(\.[0-9]+)?(-[0-9a-zA-Z.-]+)?(\+[0-9a-zA-Z.-]+)?$ ]]; then
echo "❌ Error: Version '$VERSION' does not follow format vX.Y[.Z][-PRERELEASE][+BUILD]"
echo "❌ Version must start with 'v'"
exit 1
fi
echo "✅ Version '$VERSION' format is valid"
# Check if tag already exists
if git rev-parse "$VERSION" >/dev/null 2>&1; then
echo "❌ Error: Version '$VERSION' already exists as a git tag"
echo "❌ Please update version.txt with a new version before running the release"
exit 1
fi
echo "✅ Version '$VERSION' does not exist yet - proceeding with release"
- name: 🏷️ Update Product Version
run: |
VERSION="${{ steps.get_version.outputs.version }}"
echo "$VERSION" > version.txt
- name: ⚙️ Set up Go Environment
uses: ./.github/actions/setup-go
- name: 🗄️ Cache Go Modules
uses: actions/cache@v4
id: cache-go-modules
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-modules-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-modules-
- name: 📦 Install Dependencies
run: |
cd backend
go mod download
cd ../tests/integration
go mod download
- name: 🧹 Clean Previous Builds
run: make clean
- name: 🔨 Build Product with Coverage
run: |
set -e
make build_with_coverage_only OS=$(go env GOOS) ARCH=$(go env GOARCH)
# Find the built distribution
DIST_PATH=$(find target/dist -name "thunder-*.zip" | head -1)
echo "Built distribution: $DIST_PATH"
- name: 📦 Upload Built Distribution
uses: actions/upload-artifact@v4
with:
name: thunder-distribution
path: target/dist/*.zip
if-no-files-found: error
test-integration:
name: 🧪 Integration Tests (${{ matrix.database }})
needs: build-thunder
runs-on: ubuntu-latest
strategy:
matrix:
database: [sqlite, postgres]
fail-fast: false
services:
postgres:
image: postgres:latest
env:
POSTGRES_USER: asgthunder
POSTGRES_PASSWORD: asgthunder
POSTGRES_DB: thunderdb
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: 📥 Checkout Code
uses: actions/checkout@v4
- name: ⚙️ Set up Go Environment
uses: ./.github/actions/setup-go
- name: 🗄️ Cache Go Modules
uses: actions/cache@v4
id: cache-go-modules
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-modules-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-modules-
- name: 📦 Install Dependencies
run: |
cd backend
go mod download
cd ../tests/integration
go mod download
- name: 📝 Configure Test Database
run: |
chmod +x tests/integration/resources/scripts/setup-test-config.sh
./tests/integration/resources/scripts/setup-test-config.sh
env:
DB_TYPE: ${{ matrix.database }}
- name: 🧪 Run Integration Tests (${{ matrix.database }})
uses: ./.github/actions/run-integration-tests
with:
database-type: ${{ matrix.database }}
coverage-enabled: true
validate-windows:
name: 🪟 Validate Windows PowerShell
needs: build-thunder
uses: ./.github/workflows/windows-powershell-validation.yml
build-and-package:
name: 📦 Build and Package Release
runs-on: ubuntu-latest
needs: [build-thunder, test-integration, validate-windows]
steps:
- name: 📥 Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 🏷️ Update Product Version
run: |
VERSION="${{ needs.build-thunder.outputs.version }}"
echo "$VERSION" > version.txt
- name: ⚙️ Set up Go Environment
uses: ./.github/actions/setup-go
- name: 🗄️ Cache Go Modules
uses: actions/cache@v4
id: cache-go-modules
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-modules-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-modules-
- name: 📦 Install Dependencies
run: |
cd backend
go mod download
cd ../tests/integration
go mod download
- name: 🔐 Generate and Upload Certificates
uses: ./.github/actions/generate-certificates
with:
show-cert-info: 'true'
- name: 🔨 Build Thunder Release Artifacts
uses: ./.github/actions/build-thunder-multiplatform
- name: 📝 Read Updated Version
id: version
run: echo "version=$(cat version.txt)" >> $GITHUB_OUTPUT
- name: 📦 Upload Backend Distribution Artifacts
uses: actions/upload-artifact@v4
with:
name: thunder-distribution
path: target/dist/*.zip
if-no-files-found: error
overwrite: true
- name: 📦 Upload Documentation Artifact
uses: actions/upload-artifact@v4
with:
name: thunder-docs
path: docs/build
if-no-files-found: error
- name: 🏷️ Create Git Tag
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
TAG_VERSION="${{ needs.build-thunder.outputs.version }}"
if [[ ! $TAG_VERSION == v* ]]; then
TAG_VERSION="v$TAG_VERSION"
fi
git tag -a "$TAG_VERSION" -m "Release $TAG_VERSION"
git push origin "$TAG_VERSION"
- name: 🐳 Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: 🔐 Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 📥 Download Shared Certificates for Docker
uses: actions/download-artifact@v4
with:
name: thunder-certificates
path: target/out/.cert/
- name: 📋 Prepare Docker Build Context
run: |
# Copy certificates into the Docker build context
mkdir -p docker-certs
cp target/out/.cert/server.cert docker-certs/
cp target/out/.cert/server.key docker-certs/
echo "✅ Certificates prepared for Docker build context"
- name: 🐳 Build and Push Multi-Arch Docker Image
run: |
# Convert repository name to lowercase for GHCR
REPO_NAME=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
IMAGE_NAME="ghcr.io/${REPO_NAME}"
# Get version without 'v' prefix for Docker tags
DOCKER_VERSION="${{ needs.build-thunder.outputs.version }}"
if [[ $DOCKER_VERSION == v* ]]; then
DOCKER_VERSION="${DOCKER_VERSION#v}"
fi
echo "🐳 Building and pushing Docker image: ${IMAGE_NAME}:${DOCKER_VERSION}"
# Build and push multi-arch image with version and latest tags
# Pass shared certificates as build context with paths relative to build context
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag "${IMAGE_NAME}:${DOCKER_VERSION}" \
--tag "${IMAGE_NAME}:latest" \
--build-arg CERT_FILE=docker-certs/server.cert \
--build-arg KEY_FILE=docker-certs/server.key \
--push \
.
echo "✅ Docker image pushed successfully!"
echo "📦 Image available at: ${IMAGE_NAME}:${DOCKER_VERSION}"
echo "📦 Image available at: ${IMAGE_NAME}:latest"
- name: 🏷️ Update Helm Values Image Tag
run: |
# Get version without 'v' prefix
CHART_VERSION="${{ needs.build-thunder.outputs.version }}"
if [[ $CHART_VERSION == v* ]]; then
CHART_VERSION="${CHART_VERSION#v}"
fi
echo "📝 Updating Helm values.yaml with image tag ${CHART_VERSION}"
# Check if the file exists and has the expected pattern
if ! grep -q "tag: \"" install/helm/values.yaml; then
echo "❌ Error: Could not find 'tag: \"' pattern in install/helm/values.yaml"
echo "File may have been modified or corrupted"
exit 1
fi
# Update values.yaml with the new image tag
sed -i "s/tag: \"[^\"]*\"/tag: \"${CHART_VERSION}\"/" install/helm/values.yaml
# Verify the replacement was successful
if ! grep -q "tag: \"${CHART_VERSION}\"" install/helm/values.yaml; then
echo "❌ Error: Failed to update image tag in values.yaml"
echo "Expected to find: tag: \"${CHART_VERSION}\""
echo "Current content:"
grep "tag:" install/helm/values.yaml
exit 1
fi
echo "✅ Successfully updated values.yaml with image tag: ${CHART_VERSION}"
echo "✅ Verification passed - new tag is present in file"
grep "tag:" install/helm/values.yaml | head -1
- name: ⚙️ Set up Helm
uses: azure/setup-helm@v3
with:
version: 'v3.12.3'
- name: 📦 Package and Push Helm Chart to GHCR
run: |
CHART_NAME="thunder"
OWNER_NAME=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')
HELM_REGISTRY="ghcr.io/${OWNER_NAME}"
# Get version without 'v' prefix for Helm chart version
CHART_VERSION="${{ needs.build-thunder.outputs.version }}"
if [[ $CHART_VERSION == v* ]]; then
CHART_VERSION="${CHART_VERSION#v}"
fi
echo "📦 Packaging Helm chart: ${CHART_NAME} version ${CHART_VERSION}"
# Ensure target directory exists
mkdir -p target/dist/
# Package the Helm chart
helm package install/helm --version "${CHART_VERSION}" --app-version "${CHART_VERSION}" --destination target/dist/
# Validate package was created
if [ ! -f "target/dist/${CHART_NAME}-${CHART_VERSION}.tgz" ]; then
echo "❌ Error: Helm chart package not found"
exit 1
fi
# Authenticate Helm to GHCR
echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io -u ${{ github.actor }} --password-stdin
# Push the Helm chart to GHCR
helm push "target/dist/${CHART_NAME}-${CHART_VERSION}.tgz" "oci://${HELM_REGISTRY}/helm-charts"
echo "✅ Helm chart pushed successfully!"
echo "📦 Helm chart available at: oci://${HELM_REGISTRY}/helm-charts"
- name: 📝 Calculate Next Version
id: next_version
run: |
# Get the current release version and remove 'v' prefix
RELEASE_VERSION="${{ needs.build-thunder.outputs.version }}"
if [[ $RELEASE_VERSION == v* ]]; then
RELEASE_VERSION="${RELEASE_VERSION#v}"
fi
# Parse version components (handle both X.Y and X.Y.Z formats)
if [[ $RELEASE_VERSION =~ ^([0-9]+)\.([0-9]+)\.([0-9]+) ]]; then
# X.Y.Z format
MAJOR="${BASH_REMATCH[1]}"
MINOR="${BASH_REMATCH[2]}"
PATCH="${BASH_REMATCH[3]}"
elif [[ $RELEASE_VERSION =~ ^([0-9]+)\.([0-9]+) ]]; then
# X.Y format
MAJOR="${BASH_REMATCH[1]}"
MINOR="${BASH_REMATCH[2]}"
PATCH="0"
else
echo "❌ Error: Unable to parse version format: $RELEASE_VERSION"
exit 1
fi
# Bump minor version
NEXT_MINOR=$((MINOR + 1))
NEXT_VERSION="${MAJOR}.${NEXT_MINOR}.0"
echo "✅ Next development version: $NEXT_VERSION"
echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT
- name: 🏷️ Update Product Version
run: |
NEXT_VERSION="v${{ steps.next_version.outputs.next_version }}"
echo "$NEXT_VERSION" > version.txt
echo "✅ Updated version.txt to $NEXT_VERSION"
- name: ⚙️ Set up Node.js for Version Update
uses: ./.github/actions/setup-node
with:
node-version: 'lts/*'
package-manager: 'npm'
dependency-path: 'samples/apps/react-vanilla-sample'
- name: 📦 Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: 🏷️ Update Sample Apps Version
run: |
NEXT_VERSION="${{ steps.next_version.outputs.next_version }}"
echo "📝 Setting sample apps version to $NEXT_VERSION"
# Update the react-vanilla sample app package.json
cd samples/apps/react-vanilla-sample
npm version $NEXT_VERSION --no-git-tag-version --allow-same-version
# Update the server package.json
cd server
npm version $NEXT_VERSION --no-git-tag-version --allow-same-version
cd "$GITHUB_WORKSPACE"
# Update the react-sdk sample app package.json
cd samples/apps/react-sdk-sample
pnpm version $NEXT_VERSION --no-git-tag-version --allow-same-version
cd "$GITHUB_WORKSPACE"
# Update the react-api-based sample app package.json
cd samples/apps/react-api-based-sample
pnpm version $NEXT_VERSION --no-git-tag-version --allow-same-version
cd "$GITHUB_WORKSPACE"
echo "✅ Updated sample apps version to $NEXT_VERSION"
# - name: 📈 Commit and Push Version Update
# run: |
# git config --local user.email "action@github.com"
# git config --local user.name "GitHub Action"
# NEXT_VERSION="${{ steps.next_version.outputs.next_version }}"
# # Add and commit the version changes
# git add version.txt samples/apps/react-vanilla-sample/package.json samples/apps/react-vanilla-sample/server/package.json
# if ! git diff --cached --quiet; then
# git commit -m "[Release] Update version to ${NEXT_VERSION} for the next development iteration"
# git push origin HEAD:main
# echo "✅ Pushed version update to main branch"
# else
# echo "✅ No changes to commit"
# fi
package-samples-linux:
name: 📦 Package Linux & Windows Samples
runs-on: ubuntu-latest
needs: [build-thunder, build-and-package]
steps:
- name: 📥 Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: ⚙️ Setup Samples Environment
uses: ./.github/actions/setup-samples-environment
- name: 📝 Update Sample Apps Version
uses: ./.github/actions/update-sample-versions
with:
version: ${{ needs.build-thunder.outputs.version }}
- name: 📦 Build and Package Linux Samples
run: |
./scripts/package-samples.sh linux x64
./scripts/package-samples.sh linux arm64
- name: 📦 Build and Package Windows Samples
run: ./scripts/package-samples.sh win x64
- name: 📦 Upload Linux & Windows Sample Artifacts
uses: actions/upload-artifact@v4
with:
name: thunder-samples-linux-windows
path: target/dist/*.zip
if-no-files-found: error
package-samples-macos:
name: 📦 Package macOS Samples
runs-on: macos-latest
needs: [build-thunder, build-and-package]
steps:
- name: 📥 Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: ⚙️ Setup Samples Environment
uses: ./.github/actions/setup-samples-environment
- name: 📝 Update Sample Apps Version
uses: ./.github/actions/update-sample-versions
with:
version: ${{ needs.build-thunder.outputs.version }}
- name: 📦 Build and Package macOS Samples
run: |
./scripts/package-samples.sh macos x64
./scripts/package-samples.sh macos arm64
- name: 📦 Upload macOS Sample Artifacts
uses: actions/upload-artifact@v4
with:
name: thunder-samples-macos
path: target/dist/*.zip
if-no-files-found: error
release:
name: 🚀 Release
runs-on: ubuntu-latest
needs: [build-thunder, build-and-package, package-samples-linux, package-samples-macos]
outputs:
release_tag: ${{ steps.release_info.outputs.release_tag }}
steps:
- name: 📥 Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 📥 Download Backend Artifacts
uses: actions/download-artifact@v4
with:
name: thunder-distribution
path: ./backend-artifacts
- name: 📥 Download Linux & Windows Sample Artifacts
uses: actions/download-artifact@v4
with:
name: thunder-samples-linux-windows
path: ./linux-windows-artifacts
- name: 📥 Download macOS Sample Artifacts
uses: actions/download-artifact@v4
with:
name: thunder-samples-macos
path: ./macos-artifacts
- name: 📦 Combine All Distribution Artifacts
run: |
mkdir -p target/dist
# Copy backend artifacts
cp ./backend-artifacts/*.zip target/dist/ || true
# Copy sample artifacts from each platform
cp ./linux-windows-artifacts/*.zip target/dist/ || true
cp ./macos-artifacts/*.zip target/dist/ || true
echo "✅ Combined all artifacts:"
ls -la target/dist/
- name: 📦 Upload Final Combined Artifacts
uses: actions/upload-artifact@v4
with:
name: thunder-final-distribution
path: target/dist/*.zip
if-no-files-found: error
- name: 📝 Read Version
id: version
run: |
VERSION="${{ needs.build-thunder.outputs.version }}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: 📝 Generate Automatic Release Notes
id: generate_notes
uses: actions/github-script@v7
with:
script: |
const currentTag = '${{ needs.build-thunder.outputs.version }}';
try {
// Get only the 2 most recent releases (current + previous)
const { data: releases } = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 2
});
console.log(`Found ${releases.length} recent release(s)`);
// Find the previous release (skip the current one if it exists)
let previousTag = null;
if (releases.length === 0) {
console.log('No previous releases found - this is the first release');
} else if (releases.length === 1) {
// Only one release exists
if (releases[0].tag_name === currentTag) {
console.log('Current release found, but no previous release exists');
} else {
previousTag = releases[0].tag_name;
console.log(`Previous release tag: ${previousTag}`);
}
} else {
// Two or more releases exist
if (releases[0].tag_name === currentTag) {
// Current release is the most recent, use the second one
previousTag = releases[1].tag_name;
console.log(`Current release found at position 0, using position 1: ${previousTag}`);
} else {
// Current release doesn't exist yet or is not the most recent
previousTag = releases[0].tag_name;
console.log(`Using most recent release: ${previousTag}`);
}
}
if (previousTag !== null && previousTag !== undefined) {
console.log(`Will compare ${previousTag}...${currentTag}`);
}
// Generate release notes
// Build the request parameters conditionally
const releaseNotesParams = {
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: currentTag,
};
// Only include previous_tag_name if it exists
if (previousTag !== null && previousTag !== undefined) {
releaseNotesParams.previous_tag_name = previousTag;
}
const { data } = await github.rest.repos.generateReleaseNotes(releaseNotesParams);
// Only save to file if we have actual content
const releaseNotesBody = data.body || '';
if (releaseNotesBody.trim().length > 0) {
const fs = require('fs');
fs.writeFileSync('release-notes.md', releaseNotesBody);
console.log('✅ Generated release notes successfully');
console.log(`Release notes length: ${releaseNotesBody.length} characters`);
} else {
console.log('⚠️ Generated release notes are empty, skipping file creation');
}
return releaseNotesBody;
} catch (error) {
console.log('⚠️ Could not generate release notes:', error.message);
// Return empty string if generation fails (e.g., for first release)
return '';
}
- name: 📝 Extract README Content for Release
id: readme_extract
run: |
# Get the release version without v prefix for replacement
RELEASE_VERSION="${{ needs.build-thunder.outputs.version }}"
if [[ $RELEASE_VERSION == v* ]]; then
RELEASE_VERSION="${RELEASE_VERSION#v}"
fi
# Extract introduction (everything before first --- divider)
INTRO=$(awk 'BEGIN{flag=1} /^---$/{flag=0; exit} flag{print}' README.md)
# Extract Quick Start section
QUICKSTART=$(sed -n '/^## ⚡ Quickstart/,/^---$/p' README.md | head -n -1)
# Extract license section including header
LICENSE=$(grep -A 5 "^## License" README.md)
# Replace <version> placeholders with actual version
INTRO=$(echo "$INTRO" | sed "s/<version>/$RELEASE_VERSION/g")
QUICKSTART=$(echo "$QUICKSTART" | sed "s/<version>/$RELEASE_VERSION/g")
# Replace 'latest' placeholders with actual version for release notes
INTRO=$(echo "$INTRO" | sed "s/:latest/:$RELEASE_VERSION/g")
QUICKSTART=$(echo "$QUICKSTART" | sed "s/:latest/:$RELEASE_VERSION/g")
INTRO=$(echo "$INTRO" | sed "s/latest release/$RELEASE_VERSION release/g")
QUICKSTART=$(echo "$QUICKSTART" | sed "s/latest release/$RELEASE_VERSION release/g")
# Handle other 'latest' references
INTRO=$(echo "$INTRO" | sed "s/latest release of WSO2 Thunder/$RELEASE_VERSION release of WSO2 Thunder/g")
QUICKSTART=$(echo "$QUICKSTART" | sed "s/latest release of WSO2 Thunder/$RELEASE_VERSION release of WSO2 Thunder/g")
# Add direct download links for Thunder server - replace download instruction and example paragraph
# Create the Thunder downloads table with proper newlines using printf
THUNDER_TABLE=$(printf "%s\n%s\n%s\n%s\n%s\n%s\n%s" \
" | OS | Architecture | Download Link |" \
" |-------|-------------|-------------|" \
" | macOS | ARM64 (Apple Silicon) | [thunder-${RELEASE_VERSION}-macos-arm64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/thunder-${RELEASE_VERSION}-macos-arm64.zip) |" \
" | macOS | x64 (Intel) | [thunder-${RELEASE_VERSION}-macos-x64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/thunder-${RELEASE_VERSION}-macos-x64.zip) |" \
" | Linux | x64 | [thunder-${RELEASE_VERSION}-linux-x64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/thunder-${RELEASE_VERSION}-linux-x64.zip) |" \
" | Linux | ARM64 | [thunder-${RELEASE_VERSION}-linux-arm64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/thunder-${RELEASE_VERSION}-linux-arm64.zip) |" \
" | Windows | x64 | [thunder-${RELEASE_VERSION}-win-x64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/thunder-${RELEASE_VERSION}-win-x64.zip) |")
# Replace the download instruction with the table using awk for proper handling
QUICKSTART=$(echo "$QUICKSTART" | awk -v table="$THUNDER_TABLE" '
/Download `thunder-.*-<os>-<arch>\.zip` from the \[.*release\]/ {
print table
next
}
{ print }
')
# Remove the example paragraph that follows (it's now redundant with the table)
QUICKSTART=$(echo "$QUICKSTART" | sed '/For example, if you are using a MacOS machine with a Apple Silicon (ARM64) processor, you would download `thunder-'"$RELEASE_VERSION"'-macos-arm64\.zip`\./d')
# Create the React Vanilla Sample App downloads table with proper newlines using printf
VANILLA_SAMPLE_TABLE=$(printf "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s" \
" | OS | Architecture | Download Link |" \
" |-------|-------------|-------------|" \
" | macOS | ARM64 (Apple Silicon) | [sample-app-react-vanilla-${RELEASE_VERSION}-macos-arm64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-vanilla-${RELEASE_VERSION}-macos-arm64.zip) |" \
" | macOS | x64 (Intel) | [sample-app-react-vanilla-${RELEASE_VERSION}-macos-x64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-vanilla-${RELEASE_VERSION}-macos-x64.zip) |" \
" | Linux | x64 | [sample-app-react-vanilla-${RELEASE_VERSION}-linux-x64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-vanilla-${RELEASE_VERSION}-linux-x64.zip) |" \
" | Linux | ARM64 | [sample-app-react-vanilla-${RELEASE_VERSION}-linux-arm64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-vanilla-${RELEASE_VERSION}-linux-arm64.zip) |" \
" | Windows | x64 | [sample-app-react-vanilla-${RELEASE_VERSION}-win-x64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-vanilla-${RELEASE_VERSION}-win-x64.zip) |")
# Create the React SDK Sample App downloads table with proper newlines using printf
SDK_SAMPLE_TABLE=$(printf "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s" \
" | OS | Architecture | Download Link |" \
" |-------|-------------|-------------|" \
" | macOS | ARM64 (Apple Silicon) | [sample-app-react-sdk-${RELEASE_VERSION}-macos-arm64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-sdk-${RELEASE_VERSION}-macos-arm64.zip) |" \
" | macOS | x64 (Intel) | [sample-app-react-sdk-${RELEASE_VERSION}-macos-x64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-sdk-${RELEASE_VERSION}-macos-x64.zip) |" \
" | Linux | x64 | [sample-app-react-sdk-${RELEASE_VERSION}-linux-x64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-sdk-${RELEASE_VERSION}-linux-x64.zip) |" \
" | Linux | ARM64 | [sample-app-react-sdk-${RELEASE_VERSION}-linux-arm64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-sdk-${RELEASE_VERSION}-linux-arm64.zip) |" \
" | Windows | x64 | [sample-app-react-sdk-${RELEASE_VERSION}-win-x64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-sdk-${RELEASE_VERSION}-win-x64.zip) |")
# Create the React API-based Sample App downloads table with proper newlines using printf
API_SAMPLE_TABLE=$(printf "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s" \
" | OS | Architecture | Download Link |" \
" |-------|-------------|-------------|" \
" | macOS | ARM64 (Apple Silicon) | [sample-app-react-api-based-${RELEASE_VERSION}-macos-arm64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-api-based-${RELEASE_VERSION}-macos-arm64.zip) |" \
" | macOS | x64 (Intel) | [sample-app-react-api-based-${RELEASE_VERSION}-macos-x64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-api-based-${RELEASE_VERSION}-macos-x64.zip) |" \
" | Linux | x64 | [sample-app-react-api-based-${RELEASE_VERSION}-linux-x64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-api-based-${RELEASE_VERSION}-linux-x64.zip) |" \
" | Linux | ARM64 | [sample-app-react-api-based-${RELEASE_VERSION}-linux-arm64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-api-based-${RELEASE_VERSION}-linux-arm64.zip) |" \
" | Windows | x64 | [sample-app-react-api-based-${RELEASE_VERSION}-win-x64.zip](https://github.com/${{ github.repository }}/releases/download/v${RELEASE_VERSION}/sample-app-react-api-based-${RELEASE_VERSION}-win-x64.zip) |")
# Replace the vanilla sample app download instruction with its table
QUICKSTART=$(echo "$QUICKSTART" | awk -v table="$VANILLA_SAMPLE_TABLE" '
/Download `sample-app-react-vanilla-.*-<os>-<arch>\.zip` from the \[.*release\]/ {
print table
next
}
{ print }
')
# Replace the SDK sample app download instruction with its table
QUICKSTART=$(echo "$QUICKSTART" | awk -v table="$SDK_SAMPLE_TABLE" '
/Download `sample-app-react-sdk-.*-<os>-<arch>\.zip` from the \[.*release\]/ {
print table
next
}
{ print }
')
# Replace the API-based sample app download instruction with its table
QUICKSTART=$(echo "$QUICKSTART" | awk -v table="$API_SAMPLE_TABLE" '
/Download `sample-app-react-api-based-.*-<os>-<arch>\.zip` from the \[.*release\]/ {
print table
next
}
{ print }
')
# Read the generated release notes if they exist
CHANGELOG=""
if [ -f "release-notes.md" ]; then
CHANGELOG=$(cat release-notes.md)
echo "✅ Found generated release notes"
else
echo "⚠️ No release notes file found, skipping changelog"
fi
# Combine for release description with changelog
echo "RELEASE_BODY<<EOF" >> $GITHUB_ENV
echo "$INTRO" >> $GITHUB_ENV
echo "" >> $GITHUB_ENV
# Insert changelog
if [ -n "$CHANGELOG" ]; then
echo "$CHANGELOG" >> $GITHUB_ENV
echo "" >> $GITHUB_ENV
fi
echo "$QUICKSTART" >> $GITHUB_ENV
echo "" >> $GITHUB_ENV
echo "$LICENSE" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: 📦 Create GitHub Release
id: create_release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.version.outputs.version }}
name: Thunder ${{ steps.version.outputs.version }}
draft: false
prerelease: ${{ needs.build-thunder.outputs.prerelease }}
files: target/dist/*.zip
body: ${{ env.RELEASE_BODY }}
generate_release_notes: false
- name: 🔔 Set Release Info
id: release_info
run: |
RELEASE_VERSION="${{ steps.version.outputs.version }}"
echo "release_name=Thunder ${RELEASE_VERSION}" >> $GITHUB_OUTPUT
echo "release_tag=${RELEASE_VERSION}" >> $GITHUB_OUTPUT
echo "release_url=https://github.com/${{ github.repository }}/releases/tag/${RELEASE_VERSION}" >> $GITHUB_OUTPUT
- name: 🔔 Send Release Notification
uses: ./.github/actions/release-notification
with:
webhook: ${{ secrets.GOOGLE_CHAT_WEBHOOK }}
release-name: ${{ steps.release_info.outputs.release_name }}
release-tag: ${{ steps.release_info.outputs.release_tag }}
release-url: ${{ steps.release_info.outputs.release_url }}
deploy-docs:
name: 📚 Deploy Documentation
runs-on: ubuntu-latest
needs: [build-thunder, build-and-package, release]
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: 📥 Checkout Code
uses: actions/checkout@v4
- name: 📚 Deploy Documentation
id: deployment
uses: ./.github/actions/deploy-docs
with:
docs-artifact-name: 'thunder-docs'
build-docs: 'false'
github-token: ${{ secrets.GITHUB_TOKEN }}
commit-message: '📚 Deploy documentation for ${{ needs.build-thunder.outputs.version }}'
- name: 📝 Add Docs Deployment Summary
run: |
echo "# 📚 Documentation Deployment" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Documentation for **${{ needs.build-thunder.outputs.version }}** has been deployed to GitHub Pages!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "🔗 View at: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/" >> $GITHUB_STEP_SUMMARY
trigger-performance-test:
name: 🧪 Trigger Performance Test
runs-on: ubuntu-latest
needs: [build-thunder, release, deploy-docs]
if: ${{ needs.build-thunder.outputs.run_performance_test == 'true' }}
steps:
- name: 📥 Checkout Code
uses: actions/checkout@v4
- name: ⚡ Trigger Performance Test Workflows
uses: actions/github-script@v7
with:
github-token: ${{ secrets.THUNDER_GITHUB_BOT_TOKEN }}
script: |
// Construct the Thunder pack URL using the release version
const releaseTag = '${{ needs.release.outputs.release_tag }}';
const thunderPackUrl = `https://github.com/${{ github.repository }}/releases/download/${releaseTag}/thunder-${releaseTag.replace('v', '')}-linux-x64.zip`;
const pushBenchmarkToGitHub = ${{ github.repository == 'asgardeo/thunder' }};
// Define CPU core configurations to test
const cpuCoreConfigs = ['4', '8'];
// Loop through each CPU core configuration and trigger a separate workflow
for (const cpuCores of cpuCoreConfigs) {
console.log(`🔄 Triggering performance test with ${cpuCores} CPU cores`);
try {
const result = await github.rest.actions.createWorkflowDispatch({
owner: 'asgardeo',
repo: 'thunder-performance',
workflow_id: 'vm-perf-workflow.yml',
ref: 'main',
inputs: {
THUNDER_PACK_URL: thunderPackUrl,
DEPLOYMENT: 'single-node',
CPU_CORES: cpuCores,
ADDITIONAL_PARAMS_TO_RUN_PERFORMANCE_SCRIPT: '-d 15 -w 5 -x false -y JWT',
PERFORMANCE_REPO: 'https://github.com/asgardeo/thunder-performance',
BRANCH: 'main',
MODE: 'FULL',
USE_DELAYS: 'true',
CONCURRENCY: '50-3000',
PUSH_BENCHMARKS_TO_GITHUB: pushBenchmarkToGitHub
}
});
console.log(`✅ Performance test workflow with ${cpuCores} CPU cores triggered successfully`);
} catch (error) {
console.error(`❌ Failed to trigger performance test workflow with ${cpuCores} CPU cores:`, error);
// Continue with next configuration even if one fails
}
}
// Return success
return {success: true};