Skip to content

Release

Release #60

Workflow file for this run

# Release Workflow
#
# This workflow automates the release process when semantic version tags are pushed.
# It reuses build artifacts from the build workflow (must merge to main first), validates
# the version, creates GitHub releases, and publishes to package managers.
#
# IMPORTANT: Tags must be on commits that have been merged to main and built by build.yml
#
# Triggers: Push of semantic version tag (e.g., v1.2.3)
# Performance Target: ≤10 minutes total (excluding manual approval)
# Artifacts: Reuses build artifacts, creates release packages
#
# Manual Testing on PR:
# 1. Run Build workflow manually on your PR branch first
# 2. Note the commit SHA from the build run
# 3. Use Actions tab → Release → Run workflow
# - Select your PR branch
# - Enter test version (e.g., v0.0.1-test)
# - Check 'Skip Homebrew' to avoid tap updates
# - Check 'Dry run' to skip actual release creation
# 4. Review logs to verify workflow logic
#
# Production Release:
# 1. Merge PR to main → triggers build.yml automatically
# 2. Wait for build to complete successfully
# 3. Tag the merge commit: git tag v1.0.0 && git push origin v1.0.0
# 4. Release workflow triggers automatically
name: Release
on:
push:
tags:
- 'v*.*.*' # Semantic version tags only (e.g., v1.2.3, v0.1.0)
workflow_dispatch: # Allow manual triggering for testing
inputs:
tag:
description: 'Version tag to release (e.g., v0.0.1-test for testing)'
required: true
type: string
skip_homebrew:
description: 'Skip Homebrew publication (for PR testing)'
required: false
type: boolean
default: false
skip_winget:
description: 'Skip Winget publication (for PR testing)'
required: false
type: boolean
default: false
dry_run:
description: 'Dry run - skip release creation (logs only)'
required: false
type: boolean
default: false
# Prevent concurrent releases to avoid conflicts
# Do not cancel in-progress releases as they involve publishing to external services
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
# Workflow-level permissions
permissions:
contents: write # Required for creating releases and reading repo
actions: read # Required for downloading artifacts from build workflow
packages: write # Required for GitHub Packages (bottles)
issues: write # Required for creating Winget/Chocolatey publication issues
jobs:
# Job 1: Validate Version
# Extract/validate version, ensure tag is on main
# Performance Target: <1 minute
validate-version:
name: Validate Version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.extract.outputs.version }}
commit-sha: ${{ steps.validate.outputs.commit-sha }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for release notes
- name: Extract version from tag
id: extract
run: |
# Get tag name (either from push event or manual input)
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
TAG_NAME="${{ github.event.inputs.tag }}"
else
TAG_NAME="${GITHUB_REF#refs/tags/}"
fi
# Remove 'v' prefix to get version
VERSION="${TAG_NAME#v}"
echo "📦 Tag: $TAG_NAME"
echo "🔢 Version: $VERSION"
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Validate semantic version format
run: |
VERSION="${{ steps.extract.outputs.version }}"
# Allow semver with optional pre-release/build metadata
# Valid formats: 1.2.3, 1.2.3-beta.1, 1.2.3+build.123, 1.2.3-rc.1+build.456
if ! echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$'; then
echo "❌ Error: Invalid semantic version format: $VERSION"
echo "Expected format: MAJOR.MINOR.PATCH with optional pre-release and build metadata"
echo "Examples: 1.2.3, 0.1.0-beta.1, 1.0.0-rc.1+build.123"
exit 1
fi
echo "✅ Valid version format: $VERSION"
- name: Validate tag is on main branch
id: validate
run: |
# Get the commit SHA for this tag
COMMIT_SHA=$(git rev-list -n 1 ${{ github.ref }})
echo "commit-sha=$COMMIT_SHA" >> $GITHUB_OUTPUT
echo "📍 Tag commit: $COMMIT_SHA"
# For manual testing, allow any branch
# For production tag push, enforce main branch only
if [ "${{ github.event_name }}" = "push" ]; then
# Check if this commit is on main branch
if ! git branch -r --contains $COMMIT_SHA | grep -q "origin/main"; then
echo "❌ Error: Tag must be on a commit that exists on main branch"
echo "Please merge to main first, then tag the merge commit"
exit 1
fi
echo "✅ Tag is on main branch"
else
echo "⚠️ Manual dispatch: Skipping main branch check"
echo "✅ Running on branch: ${{ github.ref_name }}"
fi
- name: Check for duplicate version in releases
env:
GH_TOKEN: ${{ github.token }}
run: |
VERSION="${{ steps.extract.outputs.version }}"
# Check if this version already exists as a release
if gh release view "v$VERSION" &>/dev/null; then
# For test versions, just warn instead of failing
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && echo "$VERSION" | grep -q -- "-"; then
echo "⚠️ Warning: Release v$VERSION already exists (test version)"
echo "💡 Consider using a different test version or deleting the existing one"
else
echo "❌ Error: Release v$VERSION already exists"
echo "Please use a new version number"
exit 1
fi
else
echo "✅ Version v$VERSION is unique"
fi
# Job 2: Build Release Artifacts
# Rebuild binaries with release version embedded (not reusing dev builds)
# Performance Target: ≤10 minutes (parallel execution)
build-release-artifacts:
name: Build ${{ matrix.platform }} Release
runs-on: ${{ matrix.os }}
needs: [validate-version]
strategy:
matrix:
include:
- os: macos-latest
platform: osx-arm64
runtime: osx-arm64
executable: tom
- os: windows-latest
platform: win-x64
runtime: win-x64
executable: tom.exe
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ needs.validate-version.outputs.commit-sha }}
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Restore dependencies
run: dotnet restore
- name: Build macOS Extension
if: startsWith(matrix.platform, 'osx-')
shell: bash
run: |
echo "🔨 Building macOS Extension for ${{ matrix.platform }}"
chmod +x src/Extensions/MacOS/build.sh
cd src/Extensions/MacOS && ./build.sh
# Verify extension was built
if [ ! -f ../../../bin/TenSecondTom.Extensions.MacOS.app/Contents/MacOS/notifier ]; then
echo "❌ Error: Extension binary not found after build"
exit 1
fi
echo "✅ Extension built successfully"
ls -la ../../../bin/TenSecondTom.Extensions.MacOS.app/Contents/MacOS/
- name: Publish ${{ matrix.platform }} executable with release version
shell: bash
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
echo "📦 Building ${{ matrix.platform }} with version: ${VERSION}"
dotnet publish src/TenSecondTom.csproj \
--configuration Release \
--runtime ${{ matrix.runtime }} \
--self-contained true \
--output ./publish \
-p:PublishSingleFile=true \
-p:Version=${VERSION}
- name: Verify Extension in Publish Output
if: startsWith(matrix.platform, 'osx-')
shell: bash
run: |
EXTENSION_PATH="./publish/TenSecondTom.Extensions.MacOS.app/Contents/MacOS/notifier"
if [ ! -f "$EXTENSION_PATH" ]; then
echo "❌ Error: Extension not found in publish output at $EXTENSION_PATH"
echo "Contents of publish directory:"
find ./publish -type f
exit 1
fi
echo "✅ Extension verified in publish directory"
ls -lh "$EXTENSION_PATH"
- name: Rename executable to 'tom' or 'tom.exe'
shell: bash
run: |
if [ "${{ matrix.platform }}" = "win-x64" ]; then
mv ./publish/TenSecondTom.exe ./publish/tom.exe
else
mv ./publish/TenSecondTom ./publish/tom
fi
- name: Verify artifact size
shell: bash
run: |
if [ "${{ runner.os }}" = "Windows" ]; then
SIZE=$(stat -c%s ./publish/${{ matrix.executable }})
else
SIZE=$(stat -f%z ./publish/${{ matrix.executable }})
fi
SIZE_MB=$((SIZE / 1024 / 1024))
echo "📦 Executable size: ${SIZE_MB}MB"
# Size limit accounts for:
# - Main binary (~28MB)
# - Microsoft AI Foundry Local SDK (~194MB)
# - Whisper.NET platform runtime (~5-100MB depending on CUDA/CoreML)
# Total expected: ~230-330MB
if [ $SIZE -gt 367001600 ]; then
echo "❌ Error: Executable exceeds 350MB limit (${SIZE_MB}MB)"
exit 1
fi
echo "✅ Size check passed: ${SIZE_MB}MB"
- name: Calculate checksum
shell: bash
run: |
cd ./publish
if [ "${{ runner.os }}" = "Windows" ]; then
sha256sum ${{ matrix.executable }} > ${{ matrix.executable }}.sha256
else
shasum -a 256 ${{ matrix.executable }} > ${{ matrix.executable }}.sha256
fi
echo "📝 SHA256:"
cat ${{ matrix.executable }}.sha256
- name: Smoke test - version command
shell: bash
run: |
if [ "${{ runner.os }}" != "Windows" ]; then
chmod +x ./publish/${{ matrix.executable }}
fi
echo "🧪 Running smoke test: --version"
./publish/${{ matrix.executable }} --version
if [ $? -eq 0 ]; then
echo "✅ Smoke test passed"
else
echo "❌ Smoke test failed"
exit 1
fi
- name: List artifact contents
shell: bash
run: |
echo "📦 Contents of publish directory:"
find ./publish -type f -exec ls -lh {} \; | head -50
echo ""
echo "📊 Total size:"
du -sh ./publish/
echo ""
echo "📊 Size by type:"
du -sh ./publish/*.dylib 2>/dev/null || true
du -sh ./publish/*.dll 2>/dev/null || true
du -sh ./publish/runtimes 2>/dev/null || true
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ten-second-tom-${{ matrix.platform }}-release
path: |
./publish/${{ matrix.executable }}
./publish/appsettings*.json
./publish/*.dylib
./publish/*.dll
./publish/*.metal
./publish/runtimes/**/*
./publish/TenSecondTom.Extensions.MacOS.app/**/*
retention-days: 90
# Job 3: Create GitHub Release
# Generate release notes and create GitHub release with all binaries
# Performance Target: ≤2 minutes
create-github-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: [validate-version, build-release-artifacts]
outputs:
release-id: ${{ steps.create-release.outputs.id }}
upload-url: ${{ steps.create-release.outputs.upload_url }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for release notes
- name: Download release artifacts
uses: actions/download-artifact@v4
with:
pattern: ten-second-tom-*-release
path: ./artifacts
- name: Package artifacts for distribution
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
echo "📦 Creating distribution packages for version ${VERSION}"
mkdir -p ./release-packages
# Package macOS ARM64
echo "Packaging macOS ARM64..."
cd ./artifacts/ten-second-tom-osx-arm64-release
tar czf ../../release-packages/ten-second-tom-${VERSION}-osx-arm64.tar.gz *
cd ../..
# Package Windows x64
echo "Packaging Windows x64..."
cd ./artifacts/ten-second-tom-win-x64-release
zip -r ../../release-packages/ten-second-tom-${VERSION}-win-x64.zip *
cd ../..
echo "✅ Distribution packages created:"
ls -lh ./release-packages/
- name: Generate release notes
id: release-notes
run: |
VERSION="v${{ needs.validate-version.outputs.version }}"
# Get previous tag for changelog
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
if [ -z "$PREV_TAG" ]; then
echo "📝 First release - no previous tag found"
NOTES="## 🎉 Initial Release
This is the first release of Ten Second Tom.
### 📦 Downloads
Choose the appropriate package for your platform:
- **macOS (Apple Silicon)**: \`ten-second-tom-${{ needs.validate-version.outputs.version }}-osx-arm64.tar.gz\`
- **Windows**: \`ten-second-tom-${{ needs.validate-version.outputs.version }}-win-x64.zip\`
### 🚀 Installation
**macOS (Apple Silicon):**
\`\`\`bash
tar xzf ten-second-tom-${{ needs.validate-version.outputs.version }}-osx-arm64.tar.gz
chmod +x tom
./tom --version
\`\`\`
**Windows:**
Extract the zip file and run \`tom.exe\` from the extracted folder."
else
echo "📝 Generating changelog from $PREV_TAG to $VERSION"
# Generate commit log
COMMITS=$(git log $PREV_TAG..HEAD --pretty=format:"- %s (%h)" --no-merges)
NOTES="## 📋 Changes
$COMMITS
### 📦 Downloads
Choose the appropriate package for your platform:
- **macOS (Apple Silicon)**: \`ten-second-tom-${{ needs.validate-version.outputs.version }}-osx-arm64.tar.gz\`
- **Windows**: \`ten-second-tom-${{ needs.validate-version.outputs.version }}-win-x64.zip\`
### 🚀 Installation
**macOS (Apple Silicon):**
\`\`\`bash
tar xzf ten-second-tom-${{ needs.validate-version.outputs.version }}-osx-arm64.tar.gz
chmod +x tom
./tom --version
\`\`\`
**Windows:**
Extract the zip file and run \`tom.exe\` from the extracted folder."
fi
# Save notes to file (handle multiline)
echo "$NOTES" > release-notes.md
cat release-notes.md
- name: Create GitHub Release
id: create-release
env:
GH_TOKEN: ${{ github.token }}
run: |
VERSION="v${{ needs.validate-version.outputs.version }}"
# Check if this is a dry run
if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then
echo "🧪 DRY RUN - Would create release $VERSION"
echo "📝 Release notes:"
cat release-notes.md
echo "⏭️ Skipping actual release creation"
exit 0
fi
# Create release with notes
gh release create "$VERSION" \
--title "Release $VERSION" \
--notes-file release-notes.md \
--draft=false \
--latest
echo "✅ GitHub release created: $VERSION"
# Check if this is a dry run
if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then
echo "🧪 DRY RUN - Skipping artifact uploads"
exit 0
fi
# Upload all distribution packages
echo "📤 Uploading distribution packages..."
gh release upload "$VERSION" \
./release-packages/* \
--clobber
echo "✅ All distribution packages uploaded"
# Job 4: Publish to Homebrew with Bottles
# Create Homebrew bottles and upload to GitHub Packages, then update tap formula
# Performance Target: ≤7 minutes
# Requires: HOMEBREW_TAP_TOKEN secret configured in 'production' environment
# Note: VS Code may show "'production' is not valid" - this is a false positive
# Can be skipped with workflow_dispatch skip_homebrew input for PR testing
publish-homebrew:
name: Publish to Homebrew
runs-on: macos-latest # Changed to macOS for bottle creation
needs: [validate-version, create-github-release]
if: ${{ github.event.inputs.skip_homebrew != 'true' && github.event.inputs.dry_run != 'true' }}
environment:
name: production # Configured in GitHub repository settings
permissions:
contents: write # Required for uploading bottles to release
packages: write # Required for GitHub Packages (bottles)
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download release artifacts
uses: actions/download-artifact@v4
with:
pattern: ten-second-tom-*-release
path: ./artifacts
- name: Create Homebrew bottles
id: bottles
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
REPO_OWNER="${{ github.repository_owner }}"
echo "🍾 Creating Homebrew bottles for version $VERSION"
# Determine macOS version for bottle tag
MACOS_VERSION=$(sw_vers -productVersion | cut -d '.' -f 1)
case $MACOS_VERSION in
12) MACOS_TAG="monterey" ;;
13) MACOS_TAG="ventura" ;;
14) MACOS_TAG="sonoma" ;;
15) MACOS_TAG="sequoia" ;;
*) MACOS_TAG="monterey" ;; # Default fallback
esac
echo "📦 Building bottles for macOS $MACOS_TAG (both architectures)"
# Create ARM64 bottle
BOTTLE_TAG_ARM64="arm64_${MACOS_TAG}"
BOTTLE_NAME_ARM64="ten-second-tom-${VERSION}.${BOTTLE_TAG_ARM64}.bottle.tar.gz"
BOTTLE_DIR_ARM64="ten-second-tom/${VERSION}/bin"
mkdir -p "$BOTTLE_DIR_ARM64"
cp "./artifacts/ten-second-tom-osx-arm64-release/tom" "$BOTTLE_DIR_ARM64/tom"
cp ./artifacts/ten-second-tom-osx-arm64-release/appsettings*.json "$BOTTLE_DIR_ARM64/" 2>/dev/null || true
cp ./artifacts/ten-second-tom-osx-arm64-release/*.dylib "$BOTTLE_DIR_ARM64/" 2>/dev/null || true
cp ./artifacts/ten-second-tom-osx-arm64-release/*.metal "$BOTTLE_DIR_ARM64/" 2>/dev/null || true
# Copy Whisper.NET CoreML runtimes
if [ -d "./artifacts/ten-second-tom-osx-arm64-release/runtimes" ]; then
cp -R "./artifacts/ten-second-tom-osx-arm64-release/runtimes" "$BOTTLE_DIR_ARM64/"
fi
# Copy macOS extension to bottle (in prefix, not bin)
EXTENSION_DIR_ARM64="ten-second-tom/${VERSION}"
cp -R "./artifacts/ten-second-tom-osx-arm64-release/TenSecondTom.Extensions.MacOS.app" "$EXTENSION_DIR_ARM64/" 2>/dev/null || true
chmod +x "$BOTTLE_DIR_ARM64/tom"
tar czf "$BOTTLE_NAME_ARM64" ten-second-tom
BOTTLE_SHA_ARM64=$(shasum -a 256 "$BOTTLE_NAME_ARM64" | cut -d ' ' -f 1)
echo "✅ ARM64 bottle: $BOTTLE_NAME_ARM64"
echo " SHA256: $BOTTLE_SHA_ARM64"
# Output variables for later steps
echo "bottle-name-arm64=$BOTTLE_NAME_ARM64" >> $GITHUB_OUTPUT
echo "bottle-tag-arm64=$BOTTLE_TAG_ARM64" >> $GITHUB_OUTPUT
echo "bottle-sha-arm64=$BOTTLE_SHA_ARM64" >> $GITHUB_OUTPUT
- name: Upload bottles to GitHub release
env:
GH_TOKEN: ${{ github.token }}
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
BOTTLE_NAME_ARM64="${{ steps.bottles.outputs.bottle-name-arm64 }}"
echo "📤 Uploading bottle to GitHub release"
# Upload ARM64 bottle to GitHub release
gh release upload "v${VERSION}" "$BOTTLE_NAME_ARM64" --clobber
echo "✅ Bottle uploaded to release assets"
echo "📦 ARM64: https://github.com/${{ github.repository }}/releases/download/v${VERSION}/${BOTTLE_NAME_ARM64}"
- name: Generate Homebrew formula with bottle blocks
id: formula
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
REPO_OWNER="${{ github.repository_owner }}"
REPO_NAME="${{ github.event.repository.name }}"
BOTTLE_TAG_ARM64="${{ steps.bottles.outputs.bottle-tag-arm64 }}"
BOTTLE_SHA_ARM64="${{ steps.bottles.outputs.bottle-sha-arm64 }}"
echo "📝 Generating Homebrew formula for version $VERSION with ARM64 bottle"
# Download source tarball to calculate SHA256
SOURCE_TARBALL_URL="https://github.com/${REPO_OWNER}/${REPO_NAME}/archive/refs/tags/v${VERSION}.tar.gz"
curl -sSL "$SOURCE_TARBALL_URL" -o source.tar.gz
SOURCE_SHA=$(shasum -a 256 source.tar.gz | cut -d ' ' -f 1)
echo "Source tarball SHA256: $SOURCE_SHA"
# Create formula file with ARM64 bottle only
{
echo "class TenSecondTom < Formula"
echo " desc \"CLI tool for daily work summaries using Claude AI with voice entry support\""
echo " homepage \"https://github.com/${REPO_OWNER}/${REPO_NAME}\""
echo " url \"https://github.com/${REPO_OWNER}/${REPO_NAME}/archive/refs/tags/v${VERSION}.tar.gz\""
echo " sha256 \"${SOURCE_SHA}\""
echo " license \"MIT\""
echo ""
echo " # Bottle (pre-built binary) for Apple Silicon"
echo " bottle do"
echo " root_url \"https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download/v${VERSION}\""
echo " sha256 cellar: :any_skip_relocation, ${BOTTLE_TAG_ARM64}: \"${BOTTLE_SHA_ARM64}\""
echo " end"
echo ""
echo " # Dependencies for voice entry feature"
echo " depends_on \"ffmpeg\""
echo ""
echo " def install"
echo " bin.install \"tom\""
echo " # Install native macOS extension for notifications"
echo " prefix.install \"TenSecondTom.Extensions.MacOS.app\" if OS.mac?"
echo " end"
echo ""
echo " def caveats"
echo " <<~EOS"
echo " Legal: Ten Second Tom is designed for single-user personal use on your own"
echo " device. Recording conversations may require consent in your jurisdiction."
echo " EOS"
echo " end"
echo ""
echo " test do"
echo " system \"#{bin}/tom\", \"--version\""
echo " end"
echo "end"
} > ten-second-tom.rb
cat ten-second-tom.rb
- name: Validate formula syntax
run: |
echo "✅ Formula syntax validation (basic check)"
# Basic syntax validation - full validation requires Homebrew installation
if ! grep -q "class TenSecondTom" ten-second-tom.rb; then
echo "❌ Error: Invalid formula structure"
exit 1
fi
# Check that source URL contains the version
if ! grep -q "archive/refs/tags/v${{ needs.validate-version.outputs.version }}.tar.gz" ten-second-tom.rb; then
echo "❌ Error: Version not found in source URL"
exit 1
fi
# Check that source has SHA256
if ! grep -q "sha256 \"" ten-second-tom.rb; then
echo "❌ Error: Source SHA256 not found in formula"
exit 1
fi
if ! grep -q "bottle do" ten-second-tom.rb; then
echo "❌ Error: Bottle block not found in formula"
exit 1
fi
echo "✅ Basic formula validation passed (including bottle block)"
- name: Push formula to Homebrew tap
env:
# Note: This secret is configured in the 'production' environment
# Go to Settings → Environments → production → Environment secrets
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
if [ -z "$TAP_TOKEN" ]; then
echo "❌ Error: HOMEBREW_TAP_TOKEN secret not configured"
echo "Please configure the secret in the 'production' environment"
echo "Settings → Environments → production → Environment secrets"
exit 1
fi
VERSION="${{ needs.validate-version.outputs.version }}"
REPO_OWNER="${{ github.repository_owner }}"
TAP_REPO="homebrew-ten-second-tom"
echo "📤 Pushing formula with bottles to ${REPO_OWNER}/${TAP_REPO}"
# Clone tap repository
git clone "https://x-access-token:${TAP_TOKEN}@github.com/${REPO_OWNER}/${TAP_REPO}.git" tap-repo
cd tap-repo
# Configure git
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Copy formula
mkdir -p Formula
cp ../ten-second-tom.rb Formula/ten-second-tom.rb
# Commit and push
git add Formula/ten-second-tom.rb
git commit -m "Release version ${VERSION} with bottles"
git push origin main
echo "✅ Formula with bottle support published to Homebrew tap"
# Job 5: Publish to Winget
# Automatically submit package update to Windows Package Manager
# Uses winget-releaser action with Komac under the hood
# Performance Target: <2 minutes
#
# Prerequisites:
# 1. WINGET_TOKEN secret configured in 'production' environment
# - Classic PAT with 'public_repo' scope
# - Create at: https://github.com/settings/tokens/new
# 2. Fork of microsoft/winget-pkgs under same account/org
# 3. First version must be submitted manually to winget-pkgs
#
# First-time setup:
# 1. Fork https://github.com/microsoft/winget-pkgs
# 2. Manually submit first version using wingetcreate:
# wingetcreate new https://github.com/sirkirby/ten-second-tom/releases/download/v1.0.0/ten-second-tom-1.0.0-win-x64.zip
# 3. After first version is merged, automation handles all future updates
publish-winget:
name: Publish to Winget
runs-on: ubuntu-latest
needs: [validate-version, create-github-release]
if: ${{ github.event.inputs.skip_winget != 'true' && github.event.inputs.dry_run != 'true' }}
environment:
name: production
steps:
- name: Publish to Winget
uses: vedantmgoyal9/winget-releaser@v2
with:
identifier: sirkirby.TenSecondTom
installers-regex: '\.zip$' # Match our Windows zip package
token: ${{ secrets.WINGET_TOKEN }}
# Optional: specify fork user if different from repo owner
# fork-user: sirkirby