Skip to content
63 changes: 49 additions & 14 deletions .github/workflows/build-and-push-images.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
workflow_dispatch:
inputs:
tag:
description: "Image tag for manual builds. If not set, the branch name is used for non-main branches."
description: "Comma-separated list of image tags for manual builds (e.g., 'preprod' or 'latest,v2,v2.1,v2.1.2'). If not set, the branch name is used for non-main branches."
required: false
type: string
push:
Expand All @@ -14,6 +14,8 @@ on:
- "**.go"
- "**/Dockerfile"
- ".github/workflows/build-and-push-images.yaml"
pull_request:
types: [opened, synchronize]

jobs:
setup:
Expand Down Expand Up @@ -52,14 +54,44 @@ jobs:
run: |
go test ./...

parse_tags:
name: Parse tags
runs-on: ubuntu-latest
outputs:
tags: ${{ steps.parse_tags.outputs.tags }}
has_custom_tags: ${{ steps.parse_tags.outputs.has_custom_tags }}
steps:
- name: Parse tags
id: parse_tags
shell: bash
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ] && [ -n "${{ github.event.inputs.tag }}" ]; then
# Parse comma-separated tags and output as multiline string for docker/metadata-action
IFS=',' read -ra TAGS <<< "${{ github.event.inputs.tag }}"
TAGS_OUTPUT=""
for tag in "${TAGS[@]}"; do
tag=$(echo "$tag" | xargs) # trim whitespace
if [ -n "$tag" ]; then
TAGS_OUTPUT="${TAGS_OUTPUT}type=raw,value=${tag}"$'\n'
fi
done
echo "tags<<EOF" >> $GITHUB_OUTPUT
echo "$TAGS_OUTPUT" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "has_custom_tags=true" >> $GITHUB_OUTPUT
else
echo "has_custom_tags=false" >> $GITHUB_OUTPUT
fi

health-checker:
name: Build health-checker image
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
environment: ${{ github.ref_name == 'main' && 'prod' || 'dev' }}
needs:
- setup
- test
- parse_tags
steps:
- name: Checkout code
id: checkout
Expand All @@ -85,10 +117,11 @@ jobs:
with:
images: ghcr.io/project-aethermesh/aetherlay/aetherlay-hc
tags: |
type=raw,value=latest,enable=${{ github.ref_name == github.event.repository.default_branch }}
type=sha,format=short,enable=${{ github.ref_name == github.event.repository.default_branch }}
type=raw,value=${{ github.event.inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag != '' }}
type=ref,event=branch,enable=${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag == '' && github.ref_name != github.event.repository.default_branch }}
type=raw,value=latest,enable=${{ github.ref_name == github.event.repository.default_branch && github.event_name != 'pull_request' }}
type=sha,format=short,enable=${{ github.ref_name == github.event.repository.default_branch && github.event_name != 'pull_request' }}
type=raw,value=pr-${{ github.event.pull_request.number }},enable=${{ github.event_name == 'pull_request' }}
${{ needs.parse_tags.outputs.tags }}
type=ref,event=branch,enable=${{ github.event_name == 'workflow_dispatch' && needs.parse_tags.outputs.has_custom_tags != 'true' && github.ref_name != github.event.repository.default_branch }}
labels: |
org.opencontainers.image.vendor=Project Aethermesh
org.opencontainers.image.licenses=AGPL-3.0
Expand All @@ -106,19 +139,20 @@ jobs:
load-balancer:
name: Build load-balancer image
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
environment: ${{ github.ref_name == 'main' && 'prod' || 'dev' }}
needs:
- setup
- test
- parse_tags
steps:
- name: Checkout code
id: checkout_lb
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Set up Go
id: setup_go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: "1.25"

Expand All @@ -136,17 +170,18 @@ jobs:
with:
images: ghcr.io/project-aethermesh/aetherlay/aetherlay-lb
tags: |
type=raw,value=latest,enable=${{ github.ref_name == github.event.repository.default_branch }}
type=sha,format=short,enable=${{ github.ref_name == github.event.repository.default_branch }}
type=raw,value=${{ github.event.inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag != '' }}
type=ref,event=branch,enable=${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag == '' && github.ref_name != github.event.repository.default_branch }}
type=raw,value=latest,enable=${{ github.ref_name == github.event.repository.default_branch && github.event_name != 'pull_request' }}
type=sha,format=short,enable=${{ github.ref_name == github.event.repository.default_branch && github.event_name != 'pull_request' }}
type=raw,value=pr-${{ github.event.pull_request.number }},enable=${{ github.event_name == 'pull_request' }}
${{ needs.parse_tags.outputs.tags }}
type=ref,event=branch,enable=${{ github.event_name == 'workflow_dispatch' && needs.parse_tags.outputs.has_custom_tags != 'true' && github.ref_name != github.event.repository.default_branch }}
labels: |
org.opencontainers.image.vendor=Project Aethermesh
org.opencontainers.image.licenses=AGPL-3.0

- name: Build and push load-balancer image
id: container_image_lb
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
file: ./services/load-balancer/Dockerfile
Expand Down
161 changes: 161 additions & 0 deletions .github/workflows/create-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
name: Create Release

on:
pull_request:
types: [opened, synchronize, closed]
branches:
- main

jobs:
version-check:
name: Check VERSION file
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.base.ref == 'main'
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.ref }}

- name: Check VERSION file exists
run: |
if [ ! -f "VERSION" ]; then
echo "❌ VERSION file not found in repository root"
echo "Please create a VERSION file with a semantic version (e.g., v1.0.0 or 1.0.0)"
exit 1
fi
echo "✅ VERSION file exists"

- name: Validate VERSION format
run: |
VERSION=$(cat VERSION | xargs)

# Remove 'v' prefix if present for validation
VERSION_CLEAN=${VERSION#v}

# Validate semantic versioning format (major.minor.patch)
if [[ ! $VERSION_CLEAN =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$ ]]; then
echo "❌ Invalid version format: $VERSION"
echo "Expected format: v1.0.0 or 1.0.0 (semantic versioning)"
exit 1
fi

echo "✅ Valid version: $VERSION"

validate-version:
name: Validate VERSION file
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true && github.event.pull_request.head.repo.full_name == github.repository
outputs:
version: ${{ steps.read_version.outputs.version }}
tags: ${{ steps.generate_tags.outputs.tags }}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Check VERSION file exists
id: check_version_file
run: |
if [ ! -f "VERSION" ]; then
echo "❌ VERSION file not found in repository root"
exit 1
fi
echo "✅ VERSION file exists"

- name: Read and validate VERSION
id: read_version
shell: bash
run: |
VERSION=$(cat VERSION | xargs)
echo "version=$VERSION" >> $GITHUB_OUTPUT

# Remove 'v' prefix if present for validation
VERSION_CLEAN=${VERSION#v}

# Validate semantic versioning format (major.minor.patch)
if [[ ! $VERSION_CLEAN =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$ ]]; then
echo "❌ Invalid version format: $VERSION"
echo "Expected format: v1.0.0 or 1.0.0 (semantic versioning)"
exit 1
fi

echo "✅ Valid version: $VERSION"

- name: Generate tags
id: generate_tags
shell: bash
run: |
VERSION="${{ steps.read_version.outputs.version }}"
# Remove 'v' prefix if present for parsing
VERSION_CLEAN=${VERSION#v}

# Extract major, minor, patch
IFS='.' read -ra VERSION_PARTS <<< "$VERSION_CLEAN"
MAJOR=${VERSION_PARTS[0]}
MINOR=${VERSION_PARTS[1]}
PATCH=${VERSION_PARTS[2]%%-*} # Remove pre-release suffix if present
PATCH=${PATCH%%+*} # Remove build metadata if present

# Ensure full version has 'v' prefix for consistency
if [[ "$VERSION" == v* ]]; then
VERSION_TAG="$VERSION"
else
VERSION_TAG="v${VERSION}"
fi

# Generate tags: latest, v{major}, v{major}.{minor}, v{full}
TAGS="latest,v${MAJOR},v${MAJOR}.${MINOR},${VERSION_TAG}"

echo "tags=$TAGS" >> $GITHUB_OUTPUT
echo "Generated tags: $TAGS"

create-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: validate-version
if: github.event.pull_request.merged == true && github.event.pull_request.head.repo.full_name == github.repository
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Create Git Tag
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
VERSION="${{ needs.validate-version.outputs.version }}"
git tag -a "$VERSION" -m "Release $VERSION"
git push origin "$VERSION"

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.validate-version.outputs.version }}
name: Release ${{ needs.validate-version.outputs.version }}
body: |
Release ${{ needs.validate-version.outputs.version }}

Merged from PR #${{ github.event.pull_request.number }}
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Trigger build workflow
uses: actions/github-script@v8
with:
script: |
const tags = '${{ needs.validate-version.outputs.tags }}';
await github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'build-and-push-images.yaml',
ref: 'main',
inputs: {
tag: tags
}
});
console.log(`Triggered build workflow with tags: ${tags}`);
Loading