feat(release): add automated release workflow and install script
Some checks failed
CI / Test (push) Successful in 26s
CI / Lint (push) Successful in 20s
CI / Build (push) Successful in 14s
Release / Create Release (push) Failing after 10s

- Embed version info in binaries via ldflags
- Create multi-platform builds, archives, and checksums
- Add Gitea release creation and asset upload in CI
- Introduce GoReleaser config for standardized builds
- Add version command and install script for easy deployment
- Update README with pre-built installation instructions
This commit is contained in:
Greg Gauthier 2026-03-01 23:25:31 +00:00
parent b8906e44c1
commit b8482b6fb0
6 changed files with 149 additions and 12 deletions

View File

@ -25,15 +25,48 @@ jobs:
- name: Build for multiple platforms
run: |
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -trimpath -o build/grokkit-linux-amd64 .
GOOS=linux GOARCH=arm64 go build -ldflags "-s -w" -trimpath -o build/grokkit-linux-arm64 .
GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w" -trimpath -o build/grokkit-darwin-amd64 .
GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w" -trimpath -o build/grokkit-darwin-arm64 .
GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -trimpath -o build/grokkit-windows-amd64.exe .
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: |
build/grokkit-*
generate_release_notes: true
VERSION=${GITHUB_REF#refs/tags/}
COMMIT=$(git rev-parse --short HEAD)
DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
mkdir -p build
for plat in 'linux/amd64' 'linux/arm64' 'darwin/amd64' 'darwin/arm64' 'windows/amd64'; do
IFS='/' read -r OS ARCH <<< "$plat"
BIN="grokkit-${OS}-${ARCH}"
if [ "$OS" = "windows" ]; then BIN="${BIN}.exe"; fi
GOOS="$OS" GOARCH="$ARCH" go build -ldflags "-s -w -X 'gmgauthier.com/grokkit/internal/version.Version=${VERSION}' -X 'gmgauthier.com/grokkit/internal/version.Commit=${COMMIT}' -X 'gmgauthier.com/grokkit/internal/version.BuildDate=${DATE}' -trimpath" -o "build/${BIN}" .
done
- name: Prepare assets
run: |
VERSION=${GITHUB_REF#refs/tags/}
for bin in build/grokkit-* ; do
if [ ! -f "$bin" ]; then continue; fi
OSARCH=$(basename "$bin" | sed 's/grokkit-//' | sed 's/\.exe$//')
tar czf "build/grokkit-${OSARCH}-${VERSION}.tar.gz" -C build "$(basename "$bin")"
done
sha256sum build/grokkit-*.tar.gz | tee build/checksums.txt
cp scripts/grokkit-install.sh build/
- name: Install dependencies
run: apt update && apt install -y jq
- name: Create Release & Upload Assets
env:
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
VERSION=${GITHUB_REF#refs/tags/}
GITEA_API=https://repos.gmgauthier.com/api/v1
# Create release
curl -X POST "${GITEA_API}/repos/${GITHUB_REPOSITORY}/releases" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"tag_name\": \"${VERSION}\",\"name\": \"Grokkit ${VERSION}\",\"body\": \"## Quick Install\\n\\n```bash\\ncurl -L https://repos.gmgauthier.com/gmgauthier/grokkit/releases/download/v${VERSION}/grokkit-install.sh | VERSION=${VERSION} bash\\n```\\n\\nAssets include platform binaries (tar.gz), checksums.txt. See CHANGELOG.md.\"}" > release.json
RELEASE_ID=$(jq .id release.json)
# Upload assets
for asset in build/* ; do
name=$(basename "$asset")
mime="application/octet-stream"
[[ "$name" =~ \.tar\.gz$ ]] && mime="application/gzip"
[[ "$name" =~ \.(txt|sh)$ ]] && mime="text/plain"
curl -X POST "${GITEA_API}/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets?name=${name}" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: ${mime}" \
--data-binary "@$asset"
done

27
.goreleaser.yaml Normal file
View File

@ -0,0 +1,27 @@
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- darwin
- windows
goarch:
- amd64
- arm64
binary: grokkit
ldflags:
- -s -w
- -X gmgauthier.com/grokkit/internal/version.Version={{.Version}}
- -X gmgauthier.com/grokkit/internal/version.Commit={{.Commit}}
- -X gmgauthier.com/grokkit/internal/version.BuildDate={{.Date}}
- -trimpath
archives:
- format: tar.gz
name_template: 'grokkit_{{.Os}}_{{.Arch}}_{{.Version}}.tar.gz'
- format: zip
name_template: 'grokkit_{{.Os}}_{{.Arch}}_{{.Version}}.zip'
os: windows
checksum:
name_template: 'checksums.txt'

View File

@ -23,6 +23,15 @@ make build
# Verify installation
grokkit --help
### From pre-built release (recommended)
```bash
VERSION=1.0.0 # Replace with latest version tag (omit 'v')
curl -L https://repos.gmgauthier.com/gmgauthier/grokkit/releases/download/v${VERSION}/grokkit-install.sh | VERSION=${VERSION} bash -
```
Verify:
```bash
grokkit version
```
## 📋 Table of Contents

View File

@ -3,9 +3,11 @@ package cmd
import (
"os"
"fmt"
"github.com/spf13/cobra"
"gmgauthier.com/grokkit/config"
"gmgauthier.com/grokkit/internal/logger"
"gmgauthier.com/grokkit/internal/version"
)
var rootCmd = &cobra.Command{
@ -35,6 +37,14 @@ func Execute() {
}
}
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version information",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("grokkit version %s (commit %s)\\n", version.Version, version.Commit)
},
}
func init() {
rootCmd.AddCommand(chatCmd)
rootCmd.AddCommand(editCmd)
@ -45,6 +55,7 @@ func init() {
rootCmd.AddCommand(historyCmd)
rootCmd.AddCommand(agentCmd)
rootCmd.AddCommand(completionCmd)
rootCmd.AddCommand(versionCmd)
// Add model flag to all commands
rootCmd.PersistentFlags().StringP("model", "m", "", "Grok model to use (overrides config)")

View File

@ -0,0 +1,7 @@
package version
var (
Version = "dev"
Commit = ""
BuildDate = ""
)

View File

@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -euo pipefail
VERSION=${VERSION:-${1:?Provide VERSION env or arg, e.g. VERSION=1.0.0 bash grokkit-install.sh}}
GITEA_BASE=https://repos.gmgauthier.com/gmgauthier/grokkit
# Detect platform
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
case &quot;$OS&quot; in
linux) OS=linux ;;
darwin) OS=darwin ;;
esac
ARCH=$(uname -m)
case &quot;$ARCH&quot; in
x86_64|amd64) ARCH=amd64 ;;
arm64|aarch64) ARCH=arm64 ;;
esac
ASSET=&quot;grokkit_${OS}_${ARCH}_${VERSION}.tar.gz&quot;
echo &quot;Installing grokkit ${VERSION} for ${OS}/${ARCH}...&quot;
TEMP_DIR=$(mktemp -d)
trap &quot;rm -rf \&quot;${TEMP_DIR}\&quot;&quot; EXIT
cd &quot;${TEMP_DIR}&quot;
# Download
curl -fL &quot;${GITEA_BASE}/releases/download/v${VERSION}/${ASSET}&quot; -o asset.tar.gz
curl -fL &quot;${GITEA_BASE}/releases/download/v${VERSION}/checksums.txt&quot; -o checksums.txt
# Verify checksum
HASH=$(grep &quot; ${ASSET}$&quot; checksums.txt | cut -d &quot; &quot; -f1)
echo &quot;${HASH} asset.tar.gz&quot; | shasum -a 256 --check - || { echo &quot;Checksum mismatch!&quot;; exit 1; }
# Extract
tar xzf asset.tar.gz
BINARY=&quot;grokkit&quot;
# Install
INSTALL_DIR=&quot;${HOME}/.local/bin&quot;
mkdir -p &quot;${INSTALL_DIR}&quot;
mv &quot;${BINARY}&quot; &quot;${INSTALL_DIR}/grokkit&quot;
chmod +x &quot;${INSTALL_DIR}/grokkit&quot;
echo &quot;✅ grokkit ${VERSION} installed to ${INSTALL_DIR}/grokkit&quot;
echo &quot;Add to PATH if needed: export PATH=\&quot;${INSTALL_DIR}:\$PATH\&quot;&quot;
grokkit version