Release #2
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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 | |
| 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 | |
| jobs: | |
| # Job 1: Validate Version and Find Artifacts | |
| # Extract/validate version, ensure tag is on main, find build artifacts | |
| # Performance Target: <2 minutes | |
| validate-version: | |
| name: Validate Version & Find Artifacts | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.extract.outputs.version }} | |
| commit-sha: ${{ steps.validate.outputs.commit-sha }} | |
| build-run-id: ${{ steps.find-artifacts.outputs.run-id }} | |
| 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 }}" | |
| # For manual testing, allow pre-release versions (e.g., 0.0.1-test) | |
| # For production, only allow strict semver (MAJOR.MINOR.PATCH) | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| # Manual dispatch: Allow semver with optional pre-release suffix | |
| if ! echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$'; then | |
| echo "❌ Error: Invalid version format: $VERSION" | |
| echo "Expected format: MAJOR.MINOR.PATCH or MAJOR.MINOR.PATCH-prerelease" | |
| echo "Examples: 1.2.3 or 0.0.1-test or 1.0.0-rc.1" | |
| exit 1 | |
| fi | |
| else | |
| # Tag push: Strict semver only (no pre-release) | |
| if ! echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then | |
| echo "❌ Error: Invalid semantic version format: $VERSION" | |
| echo "Expected format: MAJOR.MINOR.PATCH (e.g., 1.2.3)" | |
| exit 1 | |
| fi | |
| 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 | |
| - name: Find build workflow artifacts | |
| id: find-artifacts | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| COMMIT_SHA="${{ steps.validate.outputs.commit-sha }}" | |
| echo "🔍 Looking for build workflow run for commit $COMMIT_SHA..." | |
| # Find the build workflow run for this commit | |
| RUN_ID=$(gh run list \ | |
| --workflow=build.yml \ | |
| --commit=$COMMIT_SHA \ | |
| --status=success \ | |
| --json databaseId \ | |
| --jq '.[0].databaseId') | |
| if [ -z "$RUN_ID" ] || [ "$RUN_ID" = "null" ]; then | |
| echo "❌ Error: No successful build workflow run found for commit $COMMIT_SHA" | |
| echo "" | |
| echo "The release workflow reuses artifacts from the build workflow to avoid redundancy." | |
| echo "Please ensure:" | |
| echo " 1. Code has been merged to main branch" | |
| echo " 2. Build workflow has completed successfully" | |
| echo " 3. Tag is created on the same commit that was built" | |
| echo "" | |
| echo "Typical workflow:" | |
| echo " 1. Merge PR to main → triggers build.yml" | |
| echo " 2. Wait for build to complete" | |
| echo " 3. Tag the merge commit: git tag v1.0.0 && git push origin v1.0.0" | |
| exit 1 | |
| fi | |
| echo "run-id=$RUN_ID" >> $GITHUB_OUTPUT | |
| echo "✅ Found build workflow run: $RUN_ID" | |
| echo "🔗 https://github.com/${{ github.repository }}/actions/runs/$RUN_ID" | |
| # Job 2: Download Build Artifacts | |
| # Reuse artifacts from the build workflow to avoid redundant builds | |
| # Performance Target: <1 minute | |
| download-artifacts: | |
| name: Download Build Artifacts | |
| runs-on: ubuntu-latest | |
| needs: validate-version | |
| steps: | |
| - name: Download artifacts from build workflow | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| RUN_ID="${{ needs.validate-version.outputs.build-run-id }}" | |
| echo "📥 Downloading artifacts from build run $RUN_ID..." | |
| # Download all three platform artifacts | |
| gh run download $RUN_ID \ | |
| --repo ${{ github.repository }} \ | |
| --dir ./artifacts | |
| echo "✅ Downloaded artifacts:" | |
| ls -lah ./artifacts/ | |
| # Verify all expected artifacts exist | |
| for artifact in ten-second-tom-osx-x64 ten-second-tom-osx-arm64 ten-second-tom-win-x64; do | |
| if [ ! -d "./artifacts/$artifact" ]; then | |
| echo "❌ Error: Expected artifact '$artifact' not found" | |
| exit 1 | |
| fi | |
| echo " ✅ $artifact" | |
| done | |
| - name: Upload artifacts for release jobs | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-artifacts | |
| path: ./artifacts/ | |
| 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, download-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: | |
| name: release-artifacts | |
| path: ./artifacts | |
| - 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 binary for your platform: | |
| - **macOS (Intel)**: \`tom\` (from ten-second-tom-osx-x64) | |
| - **macOS (Apple Silicon)**: \`tom\` (from ten-second-tom-osx-arm64) | |
| - **Windows**: \`tom.exe\` (from ten-second-tom-win-x64) | |
| ### ✅ Verification | |
| Use \`shasum -a 256\` or \`Get-FileHash\` to verify the downloaded binaries." | |
| 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 binary for your platform: | |
| - **macOS (Intel)**: \`tom\` (from ten-second-tom-osx-x64) | |
| - **macOS (Apple Silicon)**: \`tom\` (from ten-second-tom-osx-arm64) | |
| - **Windows**: \`tom.exe\` (from ten-second-tom-win-x64) | |
| ### ✅ Verification | |
| Use \`shasum -a 256\` or \`Get-FileHash\` to verify the downloaded binaries." | |
| 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 artifacts | |
| echo "📤 Uploading artifacts..." | |
| # Upload macOS x64 | |
| gh release upload "$VERSION" \ | |
| ./artifacts/ten-second-tom-osx-x64/tom \ | |
| --clobber | |
| # Upload macOS ARM64 | |
| gh release upload "$VERSION" \ | |
| ./artifacts/ten-second-tom-osx-arm64/tom \ | |
| --clobber | |
| # Upload Windows x64 | |
| gh release upload "$VERSION" \ | |
| ./artifacts/ten-second-tom-win-x64/tom.exe \ | |
| --clobber | |
| echo "✅ All artifacts 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: read | |
| 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: | |
| name: release-artifacts | |
| 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 (e.g., arm64_monterey, monterey) | |
| 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 | |
| # Detect current architecture | |
| ARCH=$(uname -m) | |
| if [ "$ARCH" = "arm64" ]; then | |
| BOTTLE_TAG="arm64_${MACOS_TAG}" | |
| BINARY_PATH="./artifacts/ten-second-tom-osx-arm64/tom" | |
| CHECKSUM_PATH="./artifacts/ten-second-tom-osx-arm64/checksum.txt" | |
| else | |
| BOTTLE_TAG="${MACOS_TAG}" | |
| BINARY_PATH="./artifacts/ten-second-tom-osx-x64/tom" | |
| CHECKSUM_PATH="./artifacts/ten-second-tom-osx-x64/checksum.txt" | |
| fi | |
| echo "📦 Building bottle for $BOTTLE_TAG" | |
| # Create bottle directory structure | |
| BOTTLE_DIR="ten-second-tom/${VERSION}/bin" | |
| mkdir -p "$BOTTLE_DIR" | |
| # Copy binary | |
| cp "$BINARY_PATH" "$BOTTLE_DIR/tom" | |
| chmod +x "$BOTTLE_DIR/tom" | |
| # Create bottle tarball | |
| BOTTLE_NAME="ten-second-tom--${VERSION}.${BOTTLE_TAG}.bottle.tar.gz" | |
| tar czf "$BOTTLE_NAME" -C . ten-second-tom | |
| # Calculate bottle SHA256 | |
| BOTTLE_SHA=$(shasum -a 256 "$BOTTLE_NAME" | cut -d ' ' -f 1) | |
| echo "✅ Bottle created: $BOTTLE_NAME" | |
| echo " SHA256: $BOTTLE_SHA" | |
| # Output variables for later steps | |
| echo "bottle-name=$BOTTLE_NAME" >> $GITHUB_OUTPUT | |
| echo "bottle-tag=$BOTTLE_TAG" >> $GITHUB_OUTPUT | |
| echo "bottle-sha=$BOTTLE_SHA" >> $GITHUB_OUTPUT | |
| # Calculate checksums for both architectures directly from binaries | |
| SHA256_X64=$(shasum -a 256 ./artifacts/ten-second-tom-osx-x64/tom | cut -d ' ' -f 1) | |
| SHA256_ARM64=$(shasum -a 256 ./artifacts/ten-second-tom-osx-arm64/tom | cut -d ' ' -f 1) | |
| echo "sha256-x64=$SHA256_X64" >> $GITHUB_OUTPUT | |
| echo "sha256-arm64=$SHA256_ARM64" >> $GITHUB_OUTPUT | |
| echo " x64 SHA256: $SHA256_X64" | |
| echo " ARM64 SHA256: $SHA256_ARM64" | |
| - name: Upload bottle to GitHub Packages | |
| run: | | |
| VERSION="${{ needs.validate-version.outputs.version }}" | |
| REPO_OWNER="${{ github.repository_owner }}" | |
| BOTTLE_NAME="${{ steps.bottles.outputs.bottle-name }}" | |
| echo "📤 Uploading bottle to GitHub Packages (ghcr.io)" | |
| # Login to GitHub Container Registry | |
| echo "${{ github.token }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin | |
| # Use GitHub CLI to upload as package | |
| # Note: For Homebrew bottles, we use GitHub Packages generic packages | |
| # The bottle will be available at: ghcr.io/v2/$REPO_OWNER/tom/bottles/$BOTTLE_NAME | |
| # Create package metadata | |
| PACKAGE_NAME="tom" | |
| PACKAGE_URL="ghcr.io/${REPO_OWNER}/${PACKAGE_NAME}" | |
| # Upload using oras (OCI Registry As Storage) or curl to GitHub Packages API | |
| # For simplicity, we'll attach to the release as well and document the ghcr.io URL | |
| # Upload to GitHub release as backup | |
| gh release upload "v${VERSION}" "$BOTTLE_NAME" --clobber | |
| echo "✅ Bottle uploaded to release assets" | |
| echo "📦 Bottle available at: https://github.com/${REPO_OWNER}/${{ github.event.repository.name }}/releases/download/v${VERSION}/${BOTTLE_NAME}" | |
| - 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="${{ steps.bottles.outputs.bottle-tag }}" | |
| BOTTLE_SHA="${{ steps.bottles.outputs.bottle-sha }}" | |
| SHA256_X64="${{ steps.bottles.outputs.sha256-x64 }}" | |
| SHA256_ARM64="${{ steps.bottles.outputs.sha256-arm64 }}" | |
| echo "📝 Generating Homebrew formula for version $VERSION with bottle support" | |
| # Create formula file with bottle block | |
| cat > ten-second-tom.rb <<FORMULA | |
| class TenSecondTom < Formula | |
| desc "CLI tool for daily work summaries using Claude AI" | |
| homepage "https://github.com/${REPO_OWNER}/${REPO_NAME}" | |
| url "https://github.com/${REPO_OWNER}/${REPO_NAME}/archive/refs/tags/v${VERSION}.tar.gz" | |
| version "${VERSION}" | |
| license "MIT" | |
| # Bottles (pre-built binaries) for fast installation | |
| bottle do | |
| root_url "https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download/v${VERSION}" | |
| sha256 cellar: :any_skip_relocation, arm64_monterey: "${SHA256_ARM64}" | |
| sha256 cellar: :any_skip_relocation, monterey: "${SHA256_X64}" | |
| end | |
| def install | |
| bin.install "tom" | |
| end | |
| test do | |
| system "#{bin}/tom", "--version" | |
| end | |
| end | |
| FORMULA | |
| 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 | |
| if ! grep -q "version \"${{ needs.validate-version.outputs.version }}\"" ten-second-tom.rb; then | |
| echo "❌ Error: Version 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: Document Winget Publication | |
| # Generate Winget manifest and create issue for manual publication (Phase 1) | |
| # Performance Target: <1 minute | |
| # Note: Phase 2 will automate the publication process | |
| document-winget: | |
| name: Document Winget Publication | |
| runs-on: ubuntu-latest | |
| needs: [validate-version, create-github-release] | |
| if: success() # Run even if other jobs fail | |
| steps: | |
| - name: Generate Winget manifest template | |
| run: | | |
| VERSION="${{ needs.validate-version.outputs.version }}" | |
| REPO_OWNER="${{ github.repository_owner }}" | |
| REPO_NAME="${{ github.event.repository.name }}" | |
| cat > winget-manifest.yaml <<EOF | |
| # Winget Package Manifest | |
| # This manifest should be submitted to microsoft/winget-pkgs repository | |
| # Manual submission process (Phase 1) - will be automated in Phase 2 | |
| PackageIdentifier: ${REPO_OWNER}.TenSecondTom | |
| PackageVersion: ${VERSION} | |
| PackageName: Ten Second Tom | |
| Publisher: ${REPO_OWNER} | |
| License: MIT | |
| ShortDescription: CLI tool for daily work summaries using Claude AI | |
| PackageUrl: https://github.com/${REPO_OWNER}/${REPO_NAME} | |
| Installers: | |
| - Architecture: x64 | |
| InstallerType: zip | |
| InstallerUrl: https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download/v${VERSION}/tom.exe | |
| # TODO: Add SHA256 checksum from release artifact | |
| ManifestType: singleton | |
| ManifestVersion: 1.0.0 | |
| EOF | |
| cat winget-manifest.yaml | |
| - name: Create GitHub issue for manual publication | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| VERSION="${{ needs.validate-version.outputs.version }}" | |
| gh issue create \ | |
| --title "📦 Publish v${VERSION} to Winget" \ | |
| --body "## Manual Winget Publication Required | |
| Version **v${VERSION}** has been released and needs to be published to Winget. | |
| ### Steps: | |
| 1. Fork microsoft/winget-pkgs repository | |
| 2. Use the generated manifest template (see workflow artifacts) | |
| 3. Create a PR to microsoft/winget-pkgs | |
| 4. Wait for validation and merge | |
| ### References: | |
| - [Winget Package Manifest](https://github.com/microsoft/winget-pkgs) | |
| - [Release v${VERSION}](https://github.com/${{ github.repository }}/releases/tag/v${VERSION}) | |
| ### Automation: | |
| Phase 2 will automate this process." \ | |
| --label "release,winget" || echo "⚠️ Issue creation skipped (may already exist)" | |
| # Job 6: Document Chocolatey Publication | |
| # Generate Chocolatey nuspec and create issue for manual publication (Phase 1) | |
| # Performance Target: <1 minute | |
| # Note: Phase 2 will automate the publication process | |
| document-chocolatey: | |
| name: Document Chocolatey Publication | |
| runs-on: ubuntu-latest | |
| needs: [validate-version, create-github-release] | |
| if: success() # Run even if other jobs fail | |
| steps: | |
| - name: Generate Chocolatey nuspec template | |
| run: | | |
| VERSION="${{ needs.validate-version.outputs.version }}" | |
| REPO_OWNER="${{ github.repository_owner }}" | |
| REPO_NAME="${{ github.event.repository.name }}" | |
| cat > ten-second-tom.nuspec <<EOF | |
| <?xml version="1.0" encoding="utf-8"?> | |
| <!-- Chocolatey Package Specification --> | |
| <!-- Manual submission process (Phase 1) - will be automated in Phase 2 --> | |
| <package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd"> | |
| <metadata> | |
| <id>ten-second-tom</id> | |
| <version>${VERSION}</version> | |
| <title>Ten Second Tom</title> | |
| <authors>${REPO_OWNER}</authors> | |
| <projectUrl>https://github.com/${REPO_OWNER}/${REPO_NAME}</projectUrl> | |
| <licenseUrl>https://github.com/${REPO_OWNER}/${REPO_NAME}/blob/main/LICENSE</licenseUrl> | |
| <requireLicenseAcceptance>false</requireLicenseAcceptance> | |
| <description>CLI tool for daily work summaries using Claude AI</description> | |
| <summary>Daily work summary CLI powered by Claude AI</summary> | |
| <tags>cli productivity ai claude summary</tags> | |
| </metadata> | |
| <files> | |
| <file src="tools\**" target="tools" /> | |
| </files> | |
| </package> | |
| EOF | |
| cat ten-second-tom.nuspec | |
| - name: Create GitHub issue for manual publication | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| VERSION="${{ needs.validate-version.outputs.version }}" | |
| gh issue create \ | |
| --title "📦 Publish v${VERSION} to Chocolatey" \ | |
| --body "## Manual Chocolatey Publication Required | |
| Version **v${VERSION}** has been released and needs to be published to Chocolatey. | |
| ### Steps: | |
| 1. Create Chocolatey account (if not exists) | |
| 2. Use the generated nuspec template (see workflow artifacts) | |
| 3. Package and test locally: \`choco pack\` | |
| 4. Publish: \`choco push ten-second-tom.${VERSION}.nupkg --source https://push.chocolatey.org/\` | |
| ### References: | |
| - [Chocolatey Package Docs](https://docs.chocolatey.org/en-us/create/create-packages) | |
| - [Release v${VERSION}](https://github.com/${{ github.repository }}/releases/tag/v${VERSION}) | |
| ### Automation: | |
| Phase 2 will automate this process." \ | |
| --label "release,chocolatey" || echo "⚠️ Issue creation skipped (may already exist)" |