Skip to content

Merge pull request #278 from JanakaSandaruwan/test/gcp-logs-realistic… #184

Merge pull request #278 from JanakaSandaruwan/test/gcp-logs-realistic…

Merge pull request #278 from JanakaSandaruwan/test/gcp-logs-realistic… #184

Workflow file for this run

# Copyright 2026 The OpenChoreo Authors
# SPDX-License-Identifier: Apache-2.0
name: Build Images and Release Charts
on:
push:
branches: [main]
paths:
- "*/**"
workflow_dispatch:
permissions:
contents: read
packages: write
jobs:
unit-test:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Install yq
uses: mikefarah/yq@v4
# TODO: Extend language setup for non-Go modules as they are added
- name: Determine Go version
id: go-version
run: |
# Find the highest Go version across all go.mod files
GO_VERSION=$(find . -name 'go.mod' -exec grep '^go ' {} \; | awk '{print $2}' | sort -V | tail -1)
echo "version=${GO_VERSION}" >> "$GITHUB_OUTPUT"
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: ${{ steps.go-version.outputs.version }}
- name: Run unit tests for all modules
run: |
set -euo pipefail
TEST_COUNT=0
FAILED=false
for module_dir in */; do
module="${module_dir%/}"
# Skip if this module has no module.yaml
if [ ! -f "${module}/module.yaml" ]; then
continue
fi
# Skip modules without a Makefile
if [ ! -f "${module}/Makefile" ]; then
echo "Skipping ${module}: no Makefile"
continue
fi
# Skip if Makefile has no unit-test target
if ! grep -q '^unit-test:' "${module}/Makefile"; then
continue
fi
echo "::group::Testing ${module}"
make -C "${module}" unit-test
echo "::endgroup::"
TEST_COUNT=$((TEST_COUNT + 1))
done
if [ "$FAILED" = "true" ]; then
echo ""
echo "One or more modules failed unit tests."
exit 1
fi
echo ""
if [ "$TEST_COUNT" -eq 0 ]; then
echo "No modules with unit tests found."
else
echo "Successfully tested ${TEST_COUNT} module(s). ✓"
fi
- name: Upload coverage to Codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
use_oidc: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork) }}
files: ./*-coverage.out
fail_ci_if_error: false
build-and-release:
needs: unit-test
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Install yq
uses: mikefarah/yq@v4
- name: Install Helm
uses: azure/setup-helm@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to GHCR (Docker)
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to GHCR (Helm)
run: echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io --username "${{ github.actor }}" --password-stdin
- name: Build images and release charts
run: |
set -euo pipefail
REPO_OWNER=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')
GIT_SHA_SHORT=$(git rev-parse --short=8 HEAD)
EVENT_NAME="${{ github.event_name }}"
BEFORE_SHA="${{ github.event.before }}"
# Determine changed files
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
CHANGED_FILES=$(git ls-files)
elif [ -n "$BEFORE_SHA" ] && [ "$BEFORE_SHA" != "0000000000000000000000000000000000000000" ]; then
CHANGED_FILES=$(git diff --name-only "$BEFORE_SHA" HEAD)
else
CHANGED_FILES=$(git ls-files)
fi
echo "Changed files:"
echo "$CHANGED_FILES"
echo "GIT_SHA_SHORT=${GIT_SHA_SHORT}"
echo ""
for module_dir in */; do
module="${module_dir%/}"
chart_dir="${module}/helm"
# Skip directories without a helm chart
if [ ! -f "${chart_dir}/Chart.yaml" ]; then
continue
fi
# Per-module changed-file slice
MODULE_FILES=$(echo "$CHANGED_FILES" | grep "^${module}/" || true)
MODULE_CHANGED=false #Any file under the module changed
VERSION_BUMPED=false #The module's VERSION file was changed
if [ -n "$MODULE_FILES" ]; then
MODULE_CHANGED=true
fi
# Detect a VERSION-file bump for this module
VERSION_FILE="${module}/VERSION"
RELEASE_VERSION=""
if [ -f "$VERSION_FILE" ]; then
RELEASE_VERSION=$(tr -d '[:space:]' < "$VERSION_FILE")
OLD_VERSION=""
if [ -n "$BEFORE_SHA" ] && [ "$BEFORE_SHA" != "0000000000000000000000000000000000000000" ]; then
OLD_VERSION=$(git show "${BEFORE_SHA}:${VERSION_FILE}" 2>/dev/null | tr -d '[:space:]' || echo "")
fi
if [ -n "$RELEASE_VERSION" ] && [ "$RELEASE_VERSION" != "$OLD_VERSION" ]; then
VERSION_BUMPED=true
fi
fi
# workflow_dispatch: force dev publish only, never formal
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
MODULE_CHANGED=true
VERSION_BUMPED=false
fi
if [ "$MODULE_CHANGED" = "false" ] && [ "$VERSION_BUMPED" = "false" ]; then
echo "Skipping ${module}: no changes"
continue
fi
echo "::group::${module} (changed=${MODULE_CHANGED} version_bumped=${VERSION_BUMPED} release_version=${RELEASE_VERSION:-none})"
# ── Build container images ──
if [ "$MODULE_CHANGED" = "true" ] || [ "$VERSION_BUMPED" = "true" ]; then
if [ -f "${module}/module.yaml" ]; then
image_count=$(yq '.images | length' "${module}/module.yaml")
if [ "$image_count" != "0" ] && [ "$image_count" != "null" ]; then
for i in $(seq 0 $((image_count - 1))); do
image_name=$(yq ".images[${i}].name" "${module}/module.yaml")
context=$(yq ".images[${i}].context" "${module}/module.yaml")
dockerfile=$(yq ".images[${i}].dockerfile" "${module}/module.yaml")
FULL_IMAGE="ghcr.io/${REPO_OWNER}/${image_name}"
TAG_ARGS=()
if [ "$MODULE_CHANGED" = "true" ]; then
TAG_ARGS+=(-t "${FULL_IMAGE}:latest-dev")
TAG_ARGS+=(-t "${FULL_IMAGE}:${GIT_SHA_SHORT}")
fi
if [ "$VERSION_BUMPED" = "true" ]; then
TAG_ARGS+=(-t "${FULL_IMAGE}:${RELEASE_VERSION}")
fi
echo "Building and pushing ${FULL_IMAGE} with tags: ${TAG_ARGS[*]}"
docker buildx build \
--platform linux/amd64,linux/arm64 \
--push \
"${TAG_ARGS[@]}" \
-f "${module}/${dockerfile}" \
"${module}/${context}"
done
fi
fi
fi
# ── Package and publish the Helm chart ──
if [ "$MODULE_CHANGED" = "true" ] || [ "$VERSION_BUMPED" = "true" ]; then
chart_name=$(yq '.name' "${chart_dir}/Chart.yaml")
# Add dependency repos and build (once per module)
dep_count=$(yq '.dependencies | length' "${chart_dir}/Chart.yaml")
if [ "$dep_count" != "null" ] && [ "$dep_count" != "0" ]; then
for i in $(seq 0 $((dep_count - 1))); do
dep_repo=$(yq ".dependencies[${i}].repository" "${chart_dir}/Chart.yaml")
if [ -n "$dep_repo" ] && [ "$dep_repo" != "null" ]; then
dep_name="dep-$(echo "$dep_repo" | md5sum | cut -d' ' -f1)"
helm repo add "$dep_name" "$dep_repo" 2>/dev/null || true
fi
done
helm dependency build "${chart_dir}"
fi
# Each version override bakes into a separate .tgz, so package + push per target
package_and_push() {
local target_version="$1"
local target_app_version="$2"
rm -rf .packages
helm package "${chart_dir}" \
--version "${target_version}" \
--app-version "${target_app_version}" \
-d .packages
echo "Pushing ${chart_name}:${target_version} to ghcr.io/${REPO_OWNER}/helm-charts..."
helm push ".packages/${chart_name}-${target_version}.tgz" "oci://ghcr.io/${REPO_OWNER}/helm-charts"
}
if [ "$MODULE_CHANGED" = "true" ]; then
package_and_push "0.0.0-latest-dev" "latest-dev"
package_and_push "0.0.0-${GIT_SHA_SHORT}" "${GIT_SHA_SHORT}"
fi
if [ "$VERSION_BUMPED" = "true" ]; then
package_and_push "${RELEASE_VERSION}" "${RELEASE_VERSION}"
fi
fi
# ── Create and push git tag for the release ──
if [ "$VERSION_BUMPED" = "true" ]; then
TAG="${module}-${RELEASE_VERSION}"
if git rev-parse "refs/tags/${TAG}" >/dev/null 2>&1; then
echo "Tag ${TAG} already exists; skipping"
else
echo "Creating and pushing tag ${TAG}"
git tag "${TAG}" HEAD
git push origin "refs/tags/${TAG}"
fi
fi
echo "::endgroup::"
done