Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions .github/workflows/release-cli.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
name: 'Release CLI'

on:
push:
tags:
- 'cli/*'
pull_request:
paths:
- '.github/workflows/release-cli.yml'
- 'cli/Makefile'
workflow_dispatch:

# Note: tag pushes made with GITHUB_TOKEN do not trigger workflows. If CLI tagging is ever
# automated the way post-release.yml tags the server, invoke this via workflow_call instead
# of relying on the tag push.

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
build:
name: Build and Package
runs-on: ubuntu-latest
permissions:
contents: read
defaults:
run:
working-directory: cli
outputs:
version: ${{ steps.resolve.outputs.version }}
steps:
- uses: actions/checkout@v4

- name: Resolve version
id: resolve
env:
REF_TYPE: ${{ github.ref_type }}
REF_NAME: ${{ github.ref_name }}
run: |
set -euo pipefail
if [ "$REF_TYPE" = tag ]; then
V="${REF_NAME#cli/}"
V="${V#v}"
else
V="0.0.0-dev"
fi
if [[ ! "$V" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]]; then
echo "::error::resolved version '$V' is not semver (tag must be cli/X.Y.Z)"
exit 1
fi
echo "version=$V" >> "$GITHUB_OUTPUT"

- uses: actions/setup-go@v5
with:
go-version: '1.21'
cache-dependency-path: cli/go.sum

- name: Build and package
run: make package VERSION="${{ steps.resolve.outputs.version }}"

- name: Verify artifacts
env:
VERSION: ${{ steps.resolve.outputs.version }}
run: |
set -euo pipefail
out=$("./build/actionbase_${VERSION}_linux_amd64/actionbase" --version)
[ "$out" = "v${VERSION}" ] \
|| { echo "::error::--version printed '$out', want 'v${VERSION}'"; exit 1; }
for p in linux_amd64 darwin_amd64 darwin_arm64 windows_amd64; do
bin="./build/actionbase_${VERSION}_${p}/actionbase"
if [ "$p" = windows_amd64 ]; then bin="${bin}.exe"; fi
goos="${p%_*}"
goarch="${p#*_}"
info=$(go version -m "$bin")
echo "$info" | grep -qF -- "-X main.Version=${VERSION}" \
|| { echo "::error::version not linked into $p"; exit 1; }
echo "$info" | grep -qF -- "GOOS=${goos}" \
|| { echo "::error::$p was not built for GOOS=${goos}"; exit 1; }
echo "$info" | grep -qF -- "GOARCH=${goarch}" \
|| { echo "::error::$p was not built for GOARCH=${goarch}"; exit 1; }
done
for p in linux_amd64 darwin_amd64 darwin_arm64; do
d="actionbase_${VERSION}_${p}"
tar -tzf "./build/${d}.tar.gz" | grep -qxF "${d}/actionbase" \
|| { echo "::error::${d}.tar.gz layout is wrong"; exit 1; }
done
w="actionbase_${VERSION}_windows_amd64"
unzip -l "./build/${w}.zip" | grep -qF "${w}/actionbase.exe" \
|| { echo "::error::${w}.zip layout is wrong"; exit 1; }
( cd build && sha256sum -c checksums.txt ) \
|| { echo "::error::checksums.txt does not verify"; exit 1; }

- uses: actions/upload-artifact@v4
with:
name: cli-dist
path: |
cli/build/actionbase_${{ steps.resolve.outputs.version }}_*.tar.gz
cli/build/actionbase_${{ steps.resolve.outputs.version }}_*.zip
cli/build/checksums.txt
overwrite: true
retention-days: 7

publish:
name: Publish Release
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/cli/')
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
TAG: ${{ github.ref_name }}
VERSION: ${{ needs.build.outputs.version }}
steps:
- uses: actions/download-artifact@v4
with:
name: cli-dist
path: dist

- name: Check artifacts are present
run: |
set -euo pipefail
ls dist/*.tar.gz dist/*.zip dist/checksums.txt >/dev/null \
|| { echo "::error::dist/ is empty: build artifacts may have expired"; exit 1; }

- name: Create draft release if absent
run: |
set -euo pipefail
if out=$(gh release view "$TAG" --json isDraft -q .isDraft 2>&1); then
[ "$out" = true ] \
|| { echo "::error::$TAG is already published; refusing to overwrite its assets"; exit 1; }
else
case "$out" in
*"release not found"*)
{
echo "Actionbase CLI \`$VERSION\`"
echo
for f in dist/*; do echo "- ${f#dist/}"; done
echo
echo 'Verify with `sha256sum -c checksums.txt`.'
} > notes.md
gh release create "$TAG" --draft --title "$TAG" --notes-file notes.md
;;
*)
echo "$out" >&2
exit 1
;;
esac
fi

- name: Upload assets
run: gh release upload "$TAG" dist/* --clobber

- name: Summarize
run: |
url=$(gh release view "$TAG" --json url -q .url)
{
echo "### Actionbase CLI $VERSION"
echo "$url"
for f in dist/*; do echo "- ${f#dist/}"; done
echo
echo '**This release is a DRAFT.** Review the notes and click Publish.'
echo 'Leave "Set as the latest release" unchecked.'
echo 'Then update `Formula/actionbase.rb` (`url` and `sha256`).'
} >> "$GITHUB_STEP_SUMMARY"
21 changes: 20 additions & 1 deletion cli/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export CGO_ENABLED := 0

.PHONY: build clean run test install fmt vet
.PHONY: build clean run test install fmt vet package

BINARY_NAME=actionbase
MAIN_PATH=./cmd/actionbase
Expand All @@ -14,6 +14,10 @@ GOFILES=$(wildcard *.go)

LD_FLAGS := -s -w -X main.Version=$(VERSION)

PLATFORMS := linux_amd64 darwin_amd64 darwin_arm64
WIN_PLATFORM := windows_amd64
SHASUM := $(shell command -v sha256sum >/dev/null 2>&1 && echo "sha256sum" || echo "shasum -a 256")

all: fmt vet build

build:
Expand Down Expand Up @@ -84,6 +88,20 @@ build-windows:
build-all: build-linux build-macos build-windows
@echo "All builds complete"

package: build-all
@echo "Packaging..."
@cd $(BUILD_DIR) && \
rm -f checksums.txt && \
for p in $(PLATFORMS); do \
d="$(BINARY_NAME)_$(VERSION)_$$p"; \
tar --owner=0 --group=0 --numeric-owner -czf "$$d.tar.gz" "$$d" || exit 1; \
done && \
w="$(BINARY_NAME)_$(VERSION)_$(WIN_PLATFORM)" && \
rm -f "$$w.zip" && \
zip -qrX "$$w.zip" "$$w" && \
$(SHASUM) $(BINARY_NAME)_$(VERSION)_*.tar.gz $(BINARY_NAME)_$(VERSION)_*.zip > checksums.txt
@echo "Package complete: $(BUILD_DIR)"

help:
@echo "Actionbase CLI Makefile"
@echo ""
Expand All @@ -105,4 +123,5 @@ help:
@echo " build-macos - Build for macOS (AMD64 and ARM64)"
@echo " build-windows- Build for Windows AMD64"
@echo " build-all - Build for all platforms"
@echo " package - Build all platforms and create release archives"
@echo " help - Show this help message"
60 changes: 35 additions & 25 deletions cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,41 +31,51 @@ go build -o build/actionbase ./cmd/actionbase

## Release Guide

### 1. Prepare Release
Releases are automated by the [Release CLI workflow](../.github/workflows/release-cli.yml).

#### Create Version Tag
### 1. Push a Version Tag

Create a version tag before creating a release on GitHub:
```bash
git tag cli/1.0.0
git push origin cli/1.0.0
```

Use the `cli/X.Y.Z` form with no `v` prefix. The CLI prepends `v` itself when reporting
`--version`, and this matches the existing `cli/0.0.1` tag.

### 2. Publish the Draft Release

The workflow cross-compiles every platform, packages the archives, and attaches them to a
**draft** release:

- `actionbase_{VERSION}_darwin_amd64.tar.gz`
- `actionbase_{VERSION}_darwin_arm64.tar.gz`
- `actionbase_{VERSION}_linux_amd64.tar.gz`
- `actionbase_{VERSION}_windows_amd64.zip`
- `checksums.txt`

Each archive holds a single directory named after the archive, with the binary inside.

Review the draft, write the release notes, and click **Publish**. Leave *Set as the latest
release* unchecked, so the badge stays on the server release.

Afterwards, update `Formula/actionbase.rb` to point at the new tag. Its `sha256` is the hash
of GitHub's generated **source** tarball, not of any archive listed in `checksums.txt`:

```bash
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
curl -sL https://github.com/kakao/actionbase/archive/refs/tags/cli/1.0.0.tar.gz | shasum -a 256
```

#### Build Binaries for All Platforms
To reproduce the archives locally:

```bash
make build-all
cd cli
make package VERSION=1.0.0
```

This command generates binaries for the following platforms:
- `build/actionbase-linux-amd64` - Linux AMD64
- `build/actionbase-darwin-amd64` - macOS Intel
- `build/actionbase-darwin-arm64` - macOS Apple Silicon
- `build/actionbase-windows-amd64.exe` - Windows AMD64

### 2. Create GitHub Release

1. Go to the [GitHub Releases page](https://github.com/kakao/actionbase/releases)
2. Click "Draft a new release"
3. Select the tag (e.g., `v1.0.0`)
4. Write the release title and description
5. Upload the built binary files:
- `actionbase-linux-amd64`
- `actionbase-darwin-amd64`
- `actionbase-darwin-arm64`
- `actionbase-windows-amd64.exe`
6. Click "Publish release"
> The two sections below describe filenames for an `install.sh` helper that is not present
> in this repository. They do not describe what the release workflow publishes; see
> section 2 above for that.

### 3. Binary Filename Convention

Expand Down
Loading