Skip to content

Build and Release CLI #7

Build and Release CLI

Build and Release CLI #7

Workflow file for this run

name: Build and Release CLI
on:
push:
tags:
- 'cli-v*'
workflow_dispatch:
inputs:
version:
description: 'Version to release (leave blank for auto-increment)'
required: false
type: string
releaseType:
description: 'Release type'
required: true
type: choice
options:
- patch
- minor
- major
default: 'patch'
env:
GO_VERSION: '^1.23.5'
permissions:
contents: write
jobs:
prepare:
name: Prepare Release
runs-on: ubuntu-latest
outputs:
version: ${{ steps.determine_version.outputs.version }}
tag: ${{ steps.determine_version.outputs.tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Determine version
id: determine_version
run: |
# Determine if we're triggered by tag or manual workflow
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref_type }}" == "tag" ]]; then
# We're triggered by a tag push
VERSION="${GITHUB_REF#refs/tags/cmd/modcli/v}"
echo "Using version from tag: $VERSION"
else
# We're triggered by workflow_dispatch, need to calculate version
# Find the latest tag for the CLI
LATEST_TAG=$(git tag -l "cmd/modcli/v*" | sort -V | tail -n1 || echo "")
echo "Latest tag: $LATEST_TAG"
if [ -z "$LATEST_TAG" ]; then
# No existing tag, start with v0.0.0
CURRENT_VERSION="v0.0.0"
echo "No previous version found, starting with v0.0.0"
else
CURRENT_VERSION=$(echo $LATEST_TAG | sed "s|cmd/modcli/||")
echo "Current version: $CURRENT_VERSION"
fi
# Remove the 'v' prefix for semver calculations
CURRENT_VERSION_NUM=$(echo $CURRENT_VERSION | sed 's/^v//')
# Extract the parts
MAJOR=$(echo $CURRENT_VERSION_NUM | cut -d. -f1)
MINOR=$(echo $CURRENT_VERSION_NUM | cut -d. -f2)
PATCH=$(echo $CURRENT_VERSION_NUM | cut -d. -f3)
# Calculate next version based on release type
if [ "${{ github.event.inputs.releaseType }}" == "major" ]; then
VERSION="v$((MAJOR + 1)).0.0"
elif [ "${{ github.event.inputs.releaseType }}" == "minor" ]; then
VERSION="v${MAJOR}.$((MINOR + 1)).0"
else
VERSION="v${MAJOR}.${MINOR}.$((PATCH + 1))"
fi
# Use manual version if provided
if [ -n "${{ github.event.inputs.version }}" ]; then
MANUAL_VERSION="${{ github.event.inputs.version }}"
# Ensure the 'v' prefix
if [[ $MANUAL_VERSION != v* ]]; then
MANUAL_VERSION="v${MANUAL_VERSION}"
fi
VERSION="${MANUAL_VERSION}"
fi
echo "Calculated version: ${VERSION}"
fi
# Set outputs
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "tag=cmd/modcli/${VERSION}" >> $GITHUB_OUTPUT
- name: Create tag if needed
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
echo "Creating tag ${{ steps.determine_version.outputs.tag }}"
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git tag ${{ steps.determine_version.outputs.tag }} ${{ github.sha }}
git push origin ${{ steps.determine_version.outputs.tag }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build:
name: Build CLI
needs: prepare
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
include:
- os: ubuntu-latest
artifact_name: modcli
asset_name: modcli-linux-amd64
- os: windows-latest
artifact_name: modcli.exe
asset_name: modcli-windows-amd64.exe
- os: macos-latest
artifact_name: modcli
asset_name: modcli-darwin-arm64
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Build
run: |
cd cmd/modcli
go build -v -ldflags "-X github.com/GoCodeAlone/modular/cmd/modcli/cmd.Version=${{ needs.prepare.outputs.version }} -X github.com/GoCodeAlone/modular/cmd/modcli/cmd.Commit=${{ github.sha }} -X github.com/GoCodeAlone/modular/cmd/modcli/cmd.Date=$(date +'%Y-%m-%d')" -o ${{ matrix.artifact_name }}
shell: bash
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset_name }}
path: cmd/modcli/${{ matrix.artifact_name }}
release:
name: Create Release
runs-on: ubuntu-latest
needs: [prepare, build]
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for changelog generation
- name: Generate changelog
id: changelog
run: |
# Get the current tag
CURRENT_TAG="${{ needs.prepare.outputs.tag }}"
VERSION="${{ needs.prepare.outputs.version }}"
# Find the previous tag for modcli to use as starting point for changelog
PREV_TAG=$(git tag -l "cli-v*" | grep -v "$CURRENT_TAG" | sort -V | tail -n1 || echo "")
echo "Current tag: $CURRENT_TAG, version: $VERSION"
echo "Previous tag: $PREV_TAG"
# Generate changelog by looking at commits that touched the modcli directory
if [ -z "$PREV_TAG" ]; then
echo "No previous modcli tag found, including all history for modcli"
CHANGELOG=$(git log --pretty=format:"- %s (%h)" -- "cmd/modcli")
else
echo "Generating changelog from $PREV_TAG to $CURRENT_TAG"
CHANGELOG=$(git log --pretty=format:"- %s (%h)" ${PREV_TAG}..HEAD -- "cmd/modcli")
fi
# If no specific changes found for modcli
if [ -z "$CHANGELOG" ]; then
CHANGELOG="- No specific changes to modcli since last release"
fi
# Save changelog to a file with version info
echo "# Modular CLI ${VERSION}" > changelog.md
echo "" >> changelog.md
echo "## Changes" >> changelog.md
echo "" >> changelog.md
echo "$CHANGELOG" >> changelog.md
cat changelog.md
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
- name: Create release
id: create_release
run: |
# compress the artifacts
tar -czf modcli-linux-amd64.tar.gz -C ./artifacts/modcli-linux-amd64 .
zip -r modcli-windows-amd64.exe.zip ./artifacts/modcli-windows-amd64.exe
tar -czf modcli-darwin-arm64.tar.gz -C ./artifacts/modcli-darwin-arm64 .
gh release create ${{ needs.prepare.outputs.tag }} \
--title "Modular CLI ${{ needs.prepare.outputs.version }}" \
--notes-file changelog.md \
--repo ${{ github.repository }} \
--latest=false './modcli-linux-amd64.tar.gz#modcli-linux-amd64' \
'./modcli-windows-amd64.exe.zip#modcli-windows-amd64.exe' \
'./modcli-darwin-arm64.tar.gz#modcli-darwin-arm64'
git tag modcli/${{ needs.prepare.outputs.version }} $GITHUB_SHA --
git push origin modcli/${{ needs.prepare.outputs.version }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Announce to Go proxy
run: |
VERSION="${{ needs.prepare.outputs.version }}"
MODULE_NAME="github.com/GoCodeAlone/modular/cmd/modcli"
GOPROXY=proxy.golang.org go list -m ${MODULE_NAME}@${VERSION}
echo "Announced version ModCLI ${VERSION} to Go proxy"
- name: Display Release URL
run: echo "Released at ${{ steps.create_release.outputs.html_url }}"