Release devnet5 v0.5.7 #374
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 }} | |
| release_sha: ${{ steps.resolve_release.outputs.release_sha }} | |
| release_short_sha: ${{ steps.resolve_release.outputs.release_short_sha }} | |
| publish_latest: ${{ steps.resolve_release.outputs.publish_latest }} | |
| steps: | |
| - name: Checkout release PR head | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| - name: Resolve release commit | |
| id: resolve_release | |
| run: | | |
| git fetch origin main --prune --tags --force | |
| PR_HEAD_SHA=$(git rev-parse HEAD) | |
| PR_HEAD_TREE=$(git rev-parse HEAD^{tree}) | |
| MAIN_TREE=$(git rev-parse origin/main^{tree}) | |
| RELEASE_SHA="$PR_HEAD_SHA" | |
| # Empty release commits are only a PR vehicle. If the release PR head is | |
| # an empty single-parent commit, publish the parent commit instead so | |
| # git tags, Docker metadata, and devnet branches point at the code that | |
| # is actually being released. | |
| if [ "$(git rev-list --parents -n 1 HEAD | wc -w)" -eq 2 ]; then | |
| PARENT_SHA=$(git rev-parse HEAD^) | |
| PARENT_TREE=$(git rev-parse HEAD^^{tree}) | |
| if [ "$PR_HEAD_TREE" = "$PARENT_TREE" ]; then | |
| RELEASE_SHA="$PARENT_SHA" | |
| echo "ℹ️ Release PR head is an empty commit; publishing parent ${RELEASE_SHA:0:8}" | |
| fi | |
| fi | |
| RELEASE_SHORT_SHA=$(git rev-parse --short "$RELEASE_SHA") | |
| RELEASE_TREE=$(git rev-parse "$RELEASE_SHA^{tree}") | |
| echo "release_sha=$RELEASE_SHA" >> $GITHUB_OUTPUT | |
| echo "release_short_sha=$RELEASE_SHORT_SHA" >> $GITHUB_OUTPUT | |
| if [ "$RELEASE_TREE" = "$MAIN_TREE" ]; then | |
| echo "publish_latest=true" >> $GITHUB_OUTPUT | |
| echo "✅ Release tree matches current main; latest Docker tag will be published" | |
| else | |
| echo "publish_latest=false" >> $GITHUB_OUTPUT | |
| echo "ℹ️ Release tree differs from current main; skipping latest Docker tag for pinned release" | |
| fi | |
| if ! git merge-base --is-ancestor "$RELEASE_SHA" origin/main; then | |
| echo "❌ Release commit must be reachable from main history" | |
| exit 1 | |
| fi | |
| echo "✅ Release commit: $RELEASE_SHORT_SHA" | |
| - 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 }}" "${{ steps.resolve_release.outputs.release_sha }}" -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" "${{ steps.resolve_release.outputs.release_sha }}" -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 release commit | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ needs.create-tags.outputs.release_sha }} | |
| - 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 }},enable=${{ needs.create-tags.outputs.publish_latest == 'true' }} | |
| 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.16.0 | |
| - 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" | |
| # See cache-key rationale in ci.yml `lint` job (#903): include the | |
| # rust workspace Cargo.toml so profile changes bust the cache. | |
| key: ${{ runner.os }}-cargo-docker-${{ hashFiles('**/Cargo.lock', 'rust/Cargo.toml') }} | |
| - name: Build zeam natively | |
| run: | | |
| if [ "${{ matrix.arch }}" = "amd64" ]; then | |
| zig build -Doptimize=ReleaseSafe -Dtarget=x86_64-linux-gnu -Dcpu=x86_64_v3 -Drust-target-cpu=x86-64-v3 -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=${{ needs.create-tags.outputs.release_sha }} | |
| GIT_BRANCH=${{ needs.create-tags.outputs.docker_tag || github.event.pull_request.head.ref }} | |
| 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 | |
| if: ${{ needs.create-tags.outputs.publish_latest == 'true' }} | |
| 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 | |
| rebase-shadow: | |
| needs: create-tags | |
| runs-on: ubuntu-latest | |
| if: ${{ needs.create-tags.outputs.has_devnet_tag == 'true' }} | |
| outputs: | |
| shadow_status: ${{ steps.rebase.outputs.shadow_status }} | |
| shadow_sha: ${{ steps.rebase.outputs.shadow_sha }} | |
| shadow_failed: ${{ steps.rebase.outputs.shadow_failed }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Fetch all branches | |
| run: git fetch origin | |
| - name: Rebase shadow onto main and push | |
| id: rebase | |
| run: | | |
| if git ls-remote --heads origin shadow | grep -q 'refs/heads/shadow'; then | |
| echo "🔄 Rebasing shadow onto main..." | |
| git checkout -B shadow origin/shadow | |
| if git rebase origin/main; then | |
| if git push origin shadow --force-with-lease; then | |
| NEW_SHA=$(git rev-parse --short HEAD) | |
| echo "shadow_status=✅ rebased to $NEW_SHA" >> $GITHUB_OUTPUT | |
| echo "shadow_sha=$NEW_SHA" >> $GITHUB_OUTPUT | |
| echo "shadow_failed=false" >> $GITHUB_OUTPUT | |
| echo "✅ Shadow rebase succeeded: $NEW_SHA" | |
| else | |
| echo "shadow_status=❌ push failed — force-with-lease mismatch" >> $GITHUB_OUTPUT | |
| echo "shadow_sha=" >> $GITHUB_OUTPUT | |
| echo "shadow_failed=true" >> $GITHUB_OUTPUT | |
| echo "❌ Shadow push failed" | |
| exit 1 | |
| fi | |
| else | |
| git rebase --abort || true | |
| echo "shadow_status=❌ rebase conflict — manual fix needed" >> $GITHUB_OUTPUT | |
| echo "shadow_sha=" >> $GITHUB_OUTPUT | |
| echo "shadow_failed=true" >> $GITHUB_OUTPUT | |
| echo "❌ Shadow rebase failed; release will continue after notifying Telegram" | |
| exit 1 | |
| fi | |
| else | |
| echo "shadow_status=⚠️ shadow branch not found" >> $GITHUB_OUTPUT | |
| echo "shadow_sha=" >> $GITHUB_OUTPUT | |
| echo "shadow_failed=false" >> $GITHUB_OUTPUT | |
| fi | |
| create-github-release: | |
| needs: [ create-tags, build-and-push, create-manifest, rebase-shadow ] | |
| runs-on: ubuntu-latest | |
| if: | | |
| always() && | |
| needs.create-tags.result == 'success' && | |
| needs.build-and-push.result == 'success' && | |
| needs.create-manifest.result == 'success' && | |
| needs.create-tags.outputs.has_devnet_tag == 'true' | |
| steps: | |
| - name: Checkout release commit | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ needs.create-tags.outputs.release_sha }} | |
| - 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 }}" | |
| VERSION_TAG="v$VERSION" | |
| PREVIOUS_TAG="" | |
| # For devnet releases, compare against the previous devnet tag for the | |
| # same network sequence: DevnetN -> DevnetN-1. This keeps Devnet5 | |
| # changelogs anchored to Devnet4, even if version numbering is not a | |
| # perfect proxy for network transitions. For non-devnet releases, fall | |
| # back to the nearest lower vX.Y.Z version tag. | |
| if [ -n "$DEVNET_TAG" ]; then | |
| DEVNET_NUMBER="${DEVNET_TAG#Devnet}" | |
| if [ "$DEVNET_NUMBER" -gt 0 ] 2>/dev/null; then | |
| PREVIOUS_DEVNET_NUMBER=$((DEVNET_NUMBER - 1)) | |
| PREVIOUS_DEVNET_TAG="Devnet$PREVIOUS_DEVNET_NUMBER" | |
| if git rev-parse "$PREVIOUS_DEVNET_TAG" >/dev/null 2>&1; then | |
| PREVIOUS_TAG="$PREVIOUS_DEVNET_TAG" | |
| elif git rev-parse "devnet$PREVIOUS_DEVNET_NUMBER" >/dev/null 2>&1; then | |
| PREVIOUS_TAG="devnet$PREVIOUS_DEVNET_NUMBER" | |
| fi | |
| fi | |
| fi | |
| if [ -z "$PREVIOUS_TAG" ]; then | |
| while IFS= read -r TAG; do | |
| TAG_VERSION="${TAG#v}" | |
| HIGHEST=$(printf '%s\n%s\n' "$TAG_VERSION" "$VERSION" | sort -V | tail -1) | |
| if [ "$TAG_VERSION" != "$VERSION" ] && [ "$HIGHEST" = "$VERSION" ]; then | |
| PREVIOUS_TAG="$TAG" | |
| break | |
| fi | |
| done < <(git tag -l 'v[0-9]*.[0-9]*.[0-9]*' | sort -V -r) | |
| fi | |
| if [ -n "$PREVIOUS_TAG" ] && [ "$PREVIOUS_TAG" != "$VERSION_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 versioned release before $VERSION_TAG." | |
| 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 }} | |
| - **Release commit**: `${{ needs.create-tags.outputs.release_short_sha }}` | |
| - **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 (only updated when release PR head matches current main) | |
| 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" | |
| RELEASE_SHA="${{ needs.create-tags.outputs.release_sha }}" | |
| # Fetch all remotes first - ensures release commit and branches are available | |
| git fetch origin --prune --tags --force | |
| echo "✅ Updating $DEVNET_BRANCH branch to release commit ${RELEASE_SHA:0:8}" | |
| git checkout -B "$DEVNET_BRANCH" "$RELEASE_SHA" | |
| git push origin "$DEVNET_BRANCH" --force-with-lease | |
| echo "✅ Successfully pushed release commit 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 }}" | |
| REGISTRY="${{ env.REGISTRY }}" | |
| IMAGE_NAME="${{ env.IMAGE_NAME }}" | |
| SHADOW_STATUS="${{ needs.rebase-shadow.outputs.shadow_status }}" | |
| SHADOW_STATUS="${SHADOW_STATUS:-⚠️ skipped}" | |
| MESSAGE="🚀 *Zeam $GITHUB_TAG Release SUCCESS* | |
| *Release Details:* | |
| • Version: \`$VERSION\` | |
| • Network: \`$GITHUB_TAG\` | |
| • Repository: [${{ github.repository }}]($REPO_URL) | |
| *🐋 Docker Images Available:* | |
| • Multi-arch: \`$REGISTRY/$IMAGE_NAME:$DOCKER_TAG\` | |
| • AMD64: \`$REGISTRY/$IMAGE_NAME:$DOCKER_TAG-amd64\` | |
| • ARM64: \`$REGISTRY/$IMAGE_NAME:$DOCKER_TAG-arm64\` | |
| *🔗 Quick Links:* | |
| • [GitHub Release]($REPO_URL/releases/tag/$GITHUB_TAG) | |
| *🌿 Deployment:* | |
| • Code pushed to \`$DOCKER_TAG\` branch | |
| • Shadow branch: $SHADOW_STATUS | |
| _🤖 Automated release notification_" | |
| PAYLOAD=$(jq -n \ | |
| --arg chat_id "${{ secrets.TELEGRAM_CHAT_ID }}" \ | |
| --arg text "$MESSAGE" \ | |
| '{chat_id: $chat_id, text: $text, parse_mode: "Markdown", disable_web_page_preview: true}') | |
| # Send to Telegram | |
| curl -s -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \ | |
| -H "Content-Type: application/json" \ | |
| -d "$PAYLOAD" && echo "📱 Telegram notification sent successfully" || echo "❌ Failed to send Telegram notification" |