Skip to content

chore: merge shadow branch fixes and improvements to main #146

chore: merge shadow branch fixes and improvements to main

chore: merge shadow branch fixes and improvements to main #146

Workflow file for this run

name: Auto Release on Main Branch
on:
pull_request:
types: [ closed ]
branches: [ main ]
env:
REGISTRY: docker.io
IMAGE_NAME: blockblaz/zeam
permissions:
contents: write
jobs:
create-tags:
# Only run if PR was merged to main branch from release branch and has release label
if: |
github.event.pull_request.merged == true &&
github.event.pull_request.head.ref == 'release' &&
contains(github.event.pull_request.labels.*.name, 'release')
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get_tags_labels.outputs.version }}
devnet_tag: ${{ steps.get_tags_labels.outputs.devnet_tag }}
docker_tag: ${{ steps.get_tags_labels.outputs.docker_tag }}
github_tag: ${{ steps.get_tags_labels.outputs.github_tag }}
has_devnet_tag: ${{ steps.get_tags_labels.outputs.has_devnet_tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract tags from PR labels
id: get_tags_labels
run: |
# Get PR labels and extract version
LABELS='${{ toJson(github.event.pull_request.labels.*.name) }}'
echo "PR Labels: $LABELS"
# Look for version label (x.y.z format only) - MANDATORY
VERSION=$(echo $LABELS | jq -r '.[] | select(test("^[0-9]+\\.[0-9]+\\.[0-9]+$"))' | head -n 1)
# Look for devnet tags (devnet0, devnet1, devnet2, etc.)
DEVNET_TAG_LOWER=$(echo $LABELS | jq -r '.[] | select(test("^devnet[0-9]+$"))' | head -n 1)
if [ -z "$VERSION" ] || [ "$VERSION" = "null" ]; then
echo "❌ Version label is mandatory! Please add a version label in x.y.z format (e.g. 1.0.0)"
exit 1
else
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "git_tag=v$VERSION" >> $GITHUB_OUTPUT
echo "βœ… Version found: $VERSION"
fi
if [ -n "$DEVNET_TAG_LOWER" ] && [ "$DEVNET_TAG_LOWER" != "null" ]; then
# docker_tag keeps lowercase label (devnet2)
DOCKER_TAG="$DEVNET_TAG_LOWER"
# github_tag is capitalized first letter (Devnet2)
GITHUB_TAG="D${DEVNET_TAG_LOWER:1}"
echo "devnet_tag=$DOCKER_TAG" >> $GITHUB_OUTPUT
echo "docker_tag=$DOCKER_TAG" >> $GITHUB_OUTPUT
echo "github_tag=$GITHUB_TAG" >> $GITHUB_OUTPUT
echo "has_devnet_tag=true" >> $GITHUB_OUTPUT
echo "βœ… Found devnet tag: label=$DEVNET_TAG_LOWER -> docker_tag=$DOCKER_TAG, github_tag=$GITHUB_TAG"
else
echo "has_devnet_tag=false" >> $GITHUB_OUTPUT
echo "ℹ️ No devnet tag found (optional)"
fi
- name: Create and push git tags
id: create_tags
run: |
git fetch --prune --tags --force
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
CREATE_VERSION_TAG=false
CREATE_DEVNET_TAG=false
# Check if version tag should be created
if [ -n "${{ steps.get_tags_labels.outputs.version }}" ] && [ "${{ steps.get_tags_labels.outputs.version }}" != "null" ]; then
if git rev-parse "${{ steps.get_tags_labels.outputs.git_tag }}" >/dev/null 2>&1; then
echo "❌ Version tag ${{ steps.get_tags_labels.outputs.git_tag }} already exists. Please use a different version label."
exit 1
else
CREATE_VERSION_TAG=true
fi
fi
# Devnet git tag uses github_tag (DevnetX)
if [ "${{ steps.get_tags_labels.outputs.has_devnet_tag }}" = "true" ]; then
DEVNET_GIT_TAG="${{ steps.get_tags_labels.outputs.github_tag }}"
# Allow recreation by deleting local and remote
if git rev-parse "$DEVNET_GIT_TAG" >/dev/null 2>&1; then
echo "πŸ—‘οΈ Devnet tag $DEVNET_GIT_TAG already exists, will be recreated"
git tag -d "$DEVNET_GIT_TAG" || echo "⚠️ Local tag deletion failed"
git push --delete origin "$DEVNET_GIT_TAG" || echo "⚠️ Remote tag deletion failed"
fi
CREATE_DEVNET_TAG=true
fi
# Create version tag if needed
if [ "$CREATE_VERSION_TAG" = "true" ]; then
git tag -a "${{ steps.get_tags_labels.outputs.git_tag }}" -m "Release version ${{ steps.get_tags_labels.outputs.version }}"
git push origin "${{ steps.get_tags_labels.outputs.git_tag }}"
echo "βœ… Created version tag ${{ steps.get_tags_labels.outputs.git_tag }}"
fi
# Create devnet git tag (DevnetX)
if [ "$CREATE_DEVNET_TAG" = "true" ]; then
git tag -a "$DEVNET_GIT_TAG" -m "Devnet release for $DEVNET_GIT_TAG"
git push origin "$DEVNET_GIT_TAG"
echo "βœ… Created devnet git tag $DEVNET_GIT_TAG"
fi
echo "create_version_tag=$CREATE_VERSION_TAG" >> $GITHUB_OUTPUT
echo "create_devnet_tag=$CREATE_DEVNET_TAG" >> $GITHUB_OUTPUT
build-and-push:
needs: create-tags
strategy:
matrix:
include:
- runner: ubuntu-latest
arch: amd64
- runner: ubuntu-22.04-arm
arch: arm64
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest-${{ matrix.arch }}
type=raw,value=${{ needs.create-tags.outputs.version }}-${{ matrix.arch }},enable=${{ needs.create-tags.outputs.version != 'null' }}
type=raw,value=${{ needs.create-tags.outputs.docker_tag }}-${{ matrix.arch }},enable=${{ needs.create-tags.outputs.has_devnet_tag == 'true' }}
- name: Set up Zig
uses: mlugg/setup-zig@v2.0.5
with:
version: 0.15.2
- name: Set up Rust/Cargo
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: nightly
- name: Cache Zig packages
uses: actions/cache@v4
with:
path: ~/.cache/zig
key: ${{ runner.os }}-zig-packages-${{ hashFiles('build.zig.zon') }}
restore-keys: |
${{ runner.os }}-zig-packages-
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
workspaces: "rust -> target"
key: ${{ runner.os }}-cargo-docker-${{ hashFiles('**/Cargo.lock') }}
- name: Build zeam natively
run: |
if [ "${{ matrix.arch }}" = "amd64" ]; then
zig build -Doptimize=ReleaseSafe -Dtarget=x86_64-linux-gnu -Dcpu=baseline -Dgit_version="$(git rev-parse --short HEAD)"
else
zig build -Doptimize=ReleaseSafe -Dtarget=aarch64-linux-gnu -Dcpu=baseline -Dgit_version="$(git rev-parse --short HEAD)"
fi
- name: Build and push Docker image with pre-built binary (${{ matrix.arch }})
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.prebuilt
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_COMMIT=${{ github.sha }}
GIT_BRANCH=${{ github.ref_name }}
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: false
create-manifest:
needs: [ create-tags, build-and-push ]
runs-on: ubuntu-latest
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Create and push multi-arch manifest for latest
run: |
docker buildx imagetools create -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest-amd64 \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest-arm64
- name: Create and push multi-arch manifest for version tag
if: ${{ needs.create-tags.outputs.version != 'null' }}
run: |
docker buildx imagetools create -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-tags.outputs.version }} \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-tags.outputs.version }}-amd64 \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-tags.outputs.version }}-arm64
- name: Create and push multi-arch manifest for devnet tag
if: ${{ needs.create-tags.outputs.has_devnet_tag == 'true' }}
run: |
docker buildx imagetools create -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-tags.outputs.docker_tag }} \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-tags.outputs.docker_tag }}-amd64 \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-tags.outputs.docker_tag }}-arm64
create-github-release:
needs: [ create-tags, build-and-push, create-manifest ]
runs-on: ubuntu-latest
if: ${{ needs.create-tags.outputs.has_devnet_tag == 'true' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Delete existing devnet release if exists
run: |
DEVNET_TAG="${{ needs.create-tags.outputs.github_tag }}"
echo "πŸ” Checking for existing $DEVNET_TAG release..."
if gh api repos/${{ github.repository }}/releases/tags/$DEVNET_TAG >/dev/null 2>&1; then
RELEASE_ID=$(gh api repos/${{ github.repository }}/releases/tags/$DEVNET_TAG --jq '.id')
echo "πŸ—‘οΈ Found existing GitHub release for $DEVNET_TAG (ID: $RELEASE_ID), deleting..."
gh api --method DELETE repos/${{ github.repository }}/releases/$RELEASE_ID
echo "βœ… Deleted existing GitHub release"
else
echo "ℹ️ No existing GitHub release found for $DEVNET_TAG"
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Generate changelog from previous release
id: changelog
run: |
DEVNET_TAG="${{ needs.create-tags.outputs.github_tag }}"
VERSION="${{ needs.create-tags.outputs.version }}"
PREVIOUS_TAG=$(git tag -l | grep -iE "^[Dd]evnet[0-9]+" | sort -V -r | grep -v "^$DEVNET_TAG$" | head -1)
if [ -n "$PREVIOUS_TAG" ] && [ "$PREVIOUS_TAG" != "$DEVNET_TAG" ]; then
echo "βœ… Found previous tag: $PREVIOUS_TAG"
echo "πŸ“ Generating changelog from $PREVIOUS_TAG to current release..."
# Generate commit log
COMMIT_LOG=$(git log --pretty=format:"- %s (%h)" --no-merges "$PREVIOUS_TAG"..HEAD)
# Generate file changes summary
FILES_CHANGED=$(git diff --name-only "$PREVIOUS_TAG"..HEAD | wc -l)
INSERTIONS=$(git diff --shortstat "$PREVIOUS_TAG"..HEAD | grep -o '[0-9]\+ insertion' | grep -o '[0-9]\+' || echo "0")
DELETIONS=$(git diff --shortstat "$PREVIOUS_TAG"..HEAD | grep -o '[0-9]\+ deletion' | grep -o '[0-9]\+' || echo "0")
# Get contributors
CONTRIBUTORS=$(git log --pretty=format:"%an" --no-merges "$PREVIOUS_TAG"..HEAD | sort | uniq | tr '\n' ', ' | sed 's/, $//')
# Create changelog content in GitHub format
CHANGELOG="## πŸ“‹ Changes since $PREVIOUS_TAG
### πŸ“Š Summary
- **Files changed**: $FILES_CHANGED
- **Insertions**: +$INSERTIONS
- **Deletions**: -$DELETIONS
- **Contributors**: $CONTRIBUTORS
### πŸ”„ Recent commits
$COMMIT_LOG
### πŸ”— Compare changes
[View full diff](${{ github.server_url }}/${{ github.repository }}/compare/$PREVIOUS_TAG...HEAD)"
else
echo "ℹ️ No previous release found or this is the first release"
CHANGELOG="## πŸ“‹ Changes
This is the first devnet release."
fi
# Save changelog to output (escape newlines for GitHub Actions)
echo "changelog<<EOF" >> $GITHUB_OUTPUT
echo "$CHANGELOG" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "previous_tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ needs.create-tags.outputs.github_tag }}
name: "Zeam ${{ needs.create-tags.outputs.github_tag }} Release"
body: |
# Zeam ${{ needs.create-tags.outputs.github_tag }} Release
## Release Information
- **Version**: ${{ needs.create-tags.outputs.version }}
- **Network**: ${{ needs.create-tags.outputs.github_tag }}
- **Docker Images**: `${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-tags.outputs.docker_tag }}`
## πŸ“‹ Changes
${{ steps.changelog.outputs.changelog }}
## πŸ‹ Docker Images
```bash
# Multi-architecture (recommended)
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-tags.outputs.docker_tag }}
# Architecture-specific
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-tags.outputs.docker_tag }}-amd64
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-tags.outputs.docker_tag }}-arm64
```
## 🏷️ All Available Tags
```bash
# Latest release
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
# Version-specific
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-tags.outputs.version }}
# Devnet-specific
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-tags.outputs.docker_tag }}
```
draft: false
prerelease: true
- name: Push code to corresponding devnet branch
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
GITHUB_TAG="${{ needs.create-tags.outputs.github_tag }}"
DOCKER_TAG="${{ needs.create-tags.outputs.docker_tag }}"
DEVNET_BRANCH="$DOCKER_TAG" # branch = devnetX
echo "βœ… GitHub tag: $GITHUB_TAG, Docker tag/branch: $DOCKER_TAG"
if git ls-remote --heads origin "$DEVNET_BRANCH" | grep -q "$DEVNET_BRANCH"; then
echo "βœ… $DEVNET_BRANCH branch exists, updating it"
git fetch origin "$DEVNET_BRANCH"
git checkout "$DEVNET_BRANCH"
git merge main --no-edit
else
echo "βœ… $DEVNET_BRANCH branch doesn't exist, creating it from main"
git checkout -b "$DEVNET_BRANCH"
fi
git push origin "$DEVNET_BRANCH"
echo "βœ… Successfully pushed code to $DEVNET_BRANCH branch"
- name: Send Telegram success notification
if: ${{ success() }}
run: |
DOCKER_TAG="${{ needs.create-tags.outputs.docker_tag }}"
GITHUB_TAG="${{ needs.create-tags.outputs.github_tag }}"
VERSION="${{ needs.create-tags.outputs.version }}"
REPO_URL="${{ github.server_url }}/${{ github.repository }}"
MESSAGE="πŸš€ *Zeam $GITHUB_TAG Release SUCCESS*
*Release Details:*
β€’ Version: \`$VERSION\`
β€’ Network: \`$GITHUB_TAG\`
β€’ Repository: [${{ github.repository }}]($REPO_URL)
*πŸ‹ Docker Images Available:*
β€’ Multi-arch: \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$DOCKER_TAG\`
β€’ AMD64: \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$DOCKER_TAG-amd64\`
β€’ ARM64: \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$DOCKER_TAG-arm64\`
*πŸ”— Quick Links:*
β€’ [GitHub Release]($REPO_URL/releases/tag/$GITHUB_TAG)
*🌿 Deployment:*
β€’ Code pushed to \`$(echo "$DOCKER_TAG")\` branch
_πŸ€– Automated release notification_"
# Send to Telegram
curl -s -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
-H "Content-Type: application/json" \
-d "{
\"chat_id\": \"${{ secrets.TELEGRAM_CHAT_ID }}\",
\"text\": \"$MESSAGE\",
\"parse_mode\": \"Markdown\",
\"disable_web_page_preview\": true
}" && echo "πŸ“± Telegram notification sent successfully" || echo "❌ Failed to send Telegram notification"