Skip to content

Release Pipeline

Release Pipeline #9

name: Release Pipeline
on:
workflow_dispatch:
inputs:
bump_type:
description: 'Version bump type'
required: true
default: 'patch'
type: choice
options:
- major
- minor
- patch
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
new_tag: ${{ steps.next_version.outputs.new_tag }}
steps:
- name: Checkout Repository
uses: actions/checkout@v5
with:
fetch-depth: 0 # Fetch all history for changelog generation
- name: Get Latest Tag
id: get_latest_tag
run: |
# List all existing tags for debugging
echo "All existing tags:"
git tag --list 'v*.*.*' --sort=-version:refname
# Get the latest tag using version sort, or use v0.0.0 if no tags exist
LATEST_TAG=$(git tag --list 'v*.*.*' --sort=-version:refname | head -n 1)
if [ -z "$LATEST_TAG" ]; then
exit 1
fi
echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
echo "Latest tag: $LATEST_TAG"
- name: Calculate Next Version
id: next_version
run: |
LATEST_TAG="${{ steps.get_latest_tag.outputs.latest_tag }}"
# Remove 'v' prefix for calculation
VERSION=${LATEST_TAG#v}
# Split version into components
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
# Bump version based on input
case "${{ github.event.inputs.bump_type }}" in
major)
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
;;
minor)
MINOR=$((MINOR + 1))
PATCH=0
;;
patch)
PATCH=$((PATCH + 1))
;;
esac
NEW_VERSION="v${MAJOR}.${MINOR}.${PATCH}"
echo "new_tag=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "New version: $NEW_VERSION"
- name: Generate Changelog
id: changelog
run: |
LATEST_TAG="${{ steps.get_latest_tag.outputs.latest_tag }}"
NEW_TAG="${{ steps.next_version.outputs.new_tag }}"
echo "# Release $NEW_TAG" > RELEASE_CHANGELOG.md
echo "" >> RELEASE_CHANGELOG.md
echo "## Changes since $LATEST_TAG" >> RELEASE_CHANGELOG.md
echo "" >> RELEASE_CHANGELOG.md
# Generate changelog from commits
if [ "$LATEST_TAG" = "v0.0.0" ]; then
# First release - include all commits
git log --pretty=format:"- %s (%h)" >> RELEASE_CHANGELOG.md
else
# Get commits since last tag
git log ${LATEST_TAG}..HEAD --pretty=format:"- %s (%h)" >> RELEASE_CHANGELOG.md
fi
echo "" >> RELEASE_CHANGELOG.md
echo "" >> RELEASE_CHANGELOG.md
echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LATEST_TAG}...${NEW_TAG}" >> RELEASE_CHANGELOG.md
cat RELEASE_CHANGELOG.md
- name: Create Tag
id: create_tag
uses: rickstaa/action-create-tag@v1
with:
tag: ${{ steps.next_version.outputs.new_tag }}
message: "Release ${{ steps.next_version.outputs.new_tag }}"
force_push_tag: false
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Create Release Archive
id: create_archive
run: |
NEW_TAG="${{ steps.next_version.outputs.new_tag }}"
ARCHIVE_NAME="vteam-${NEW_TAG}.tar.gz"
# Create archive of entire repository at this tag
git archive --format=tar.gz --prefix=vteam-${NEW_TAG}/ HEAD > $ARCHIVE_NAME
echo "archive_name=$ARCHIVE_NAME" >> $GITHUB_OUTPUT
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.next_version.outputs.new_tag }}
name: "Release ${{ steps.next_version.outputs.new_tag }}"
body_path: RELEASE_CHANGELOG.md
draft: false
prerelease: false
files: |
${{ steps.create_archive.outputs.archive_name }}
RELEASE_CHANGELOG.md
build-and-push:
runs-on: ubuntu-latest
needs: release
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
strategy:
matrix:
component:
- name: frontend
context: ./components/frontend
image: quay.io/ambient_code/vteam_frontend
dockerfile: ./components/frontend/Dockerfile
- name: backend
context: ./components/backend
image: quay.io/ambient_code/vteam_backend
dockerfile: ./components/backend/Dockerfile
- name: operator
context: ./components/operator
image: quay.io/ambient_code/vteam_operator
dockerfile: ./components/operator/Dockerfile
- name: claude-code-runner
context: ./components/runners
image: quay.io/ambient_code/vteam_claude_runner
dockerfile: ./components/runners/claude-code-runner/Dockerfile
steps:
- name: Checkout code from the tag generated above
uses: actions/checkout@v5
with:
ref: ${{ needs.release.outputs.new_tag }}
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
platforms: linux/amd64,linux/arm64
- name: Log in to Quay.io
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_PASSWORD }}
- name: Log in to Red Hat Container Registry
uses: docker/login-action@v3
with:
registry: registry.redhat.io
username: ${{ secrets.REDHAT_USERNAME }}
password: ${{ secrets.REDHAT_PASSWORD }}
- name: Build and push ${{ matrix.component.name }} image
uses: docker/build-push-action@v6
with:
context: ${{ matrix.component.context }}
file: ${{ matrix.component.dockerfile }}
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ matrix.component.image }}:${{ needs.release.outputs.new_tag }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy-to-openshift:
runs-on: ubuntu-latest
needs: [release, build-and-push]
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Install oc
uses: redhat-actions/oc-installer@v1
with:
oc_version: 'latest'
- name: Log in to OpenShift Cluster
run: |
oc login ${{ secrets.PROD_OPENSHIFT_SERVER }} --token=${{ secrets.PROD_OPENSHIFT_TOKEN }} --insecure-skip-tls-verify
- name: Delete deployments in ambient-code namespace to force re-deploy
run: |
oc delete deployment --all -n ambient-code
- name: Deploy updated components to OpenShift
run: |
oc apply -k components/manifests
- name: Update frontend if changed
run: |
oc patch deployment frontend -n ambient-code --patch "{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"frontend\",\"image\":\"quay.io/ambient_code/vteam_frontend:${{ needs.release.outputs.new_tag }}\",\"env\":[{\"name\":\"BACKEND_URL\",\"value\":\"http://backend-service:8080/api\"},{\"name\":\"NODE_ENV\",\"value\":\"production\"},{\"name\":\"GITHUB_APP_SLUG\",\"value\":\"ambient-code\"},{\"name\":\"VTEAM_VERSION\",\"value\":\"${{ needs.release.outputs.new_tag }}\"}]}]}}}}"
- name: Update backend if changed
run: |
oc patch deployment backend-api -n ambient-code --patch "{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"backend-api\",\"image\":\"quay.io/ambient_code/vteam_backend:${{ needs.release.outputs.new_tag }}\"}]}}}}"
- name: Update operator image and environment variables
run: |
oc patch deployment agentic-operator -n ambient-code --patch "{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"agentic-operator\",\"image\":\"quay.io/ambient_code/vteam_operator:${{ needs.release.outputs.new_tag }}\"}]}}}}"
oc patch deployment agentic-operator -n ambient-code --type=json -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/env", "value": [{"name":"NAMESPACE","valueFrom":{"fieldRef":{"fieldPath":"metadata.namespace"}}},{"name":"BACKEND_NAMESPACE","valueFrom":{"fieldRef":{"fieldPath":"metadata.namespace"}}},{"name":"BACKEND_API_URL","value":"http://backend-service:8080/api"},{"name":"AMBIENT_CODE_RUNNER_IMAGE","value":"quay.io/ambient_code/vteam_claude_runner:${{ needs.release.outputs.new_tag }}"},{"name":"CONTENT_SERVICE_IMAGE","value":"quay.io/ambient_code/vteam_backend:${{ needs.release.outputs.new_tag }}"},{"name":"IMAGE_PULL_POLICY","value":"Always"}]}]'