name: Release
on:
push:
branches:
- main
tags:
- "v*"
workflow_dispatch:
permissions:
contents: write
pull-requests: write
issues: write
jobs:
release-please:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
version: ${{ steps.release.outputs.version }}
steps:
- uses: googleapis/release-please-action@v4
id: release
with:
token: ${{ secrets.GITHUB_TOKEN }}
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
check-tag:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
outputs:
is_tag: "true"
tag_name: ${{ github.ref_name }}
steps:
- name: Tag detected
run: |
echo "Tag push detected: ${{ github.ref_name }}"
echo "This will trigger the full release process"
crates-publish:
name: Publish to crates.io
runs-on: windows-latest
needs: [release-please, check-tag]
if: |
always() &&
((needs.release-please.result == 'success' && needs.release-please.outputs.release_created == 'true') ||
(needs.check-tag.result == 'success' && needs.check-tag.outputs.is_tag == 'true'))
steps:
- uses: actions/checkout@v6
- name: Setup vx
uses: loonghao/vx@main
with:
version: '0.8.0'
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup tools (vx)
run: vx setup
- name: Add Rust components
run: vx rustup component add clippy rustfmt
- name: Setup MSVC Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1
- name: Fix MSVC linker (remove Git's link.exe)
run: Remove-Item 'C:\Program Files\Git\usr\bin\link.exe' -Force -ErrorAction SilentlyContinue
shell: pwsh
- name: Cache cargo
uses: Swatinem/rust-cache@v2
- name: Publish to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
# Check if package version already exists on crates.io
$packageVersion = (Select-String -Path "Cargo.toml" -Pattern '^version = "([^"]+)"').Matches.Groups[1].Value
$packageName = "msvc-kit"
# Use crates.io API for reliable version check (cargo search output parsing is fragile)
try {
$response = Invoke-RestMethod -Uri "https://crates.io/api/v1/crates/$packageName" -Headers @{ "User-Agent" = "msvc-kit-ci" }
$existingVersion = $response.crate.newest_version
Write-Host "Current version on crates.io: $existingVersion"
} catch {
Write-Host "Warning: Could not fetch version from crates.io: $_"
$existingVersion = $null
}
if ($existingVersion -eq $packageVersion) {
Write-Host "Package $packageName v$packageVersion already exists on crates.io, skipping publish"
exit 0
}
Write-Host "Publishing $packageName v$packageVersion to crates.io..."
vx just publish-ci
build-release-binary:
name: Build Windows x64 binary
runs-on: windows-latest
needs: [release-please, check-tag]
if: |
always() &&
((needs.release-please.result == 'success' && needs.release-please.outputs.release_created == 'true') ||
(needs.check-tag.result == 'success' && needs.check-tag.outputs.is_tag == 'true'))
steps:
- uses: actions/checkout@v6
- name: Setup vx
uses: loonghao/vx@main
with:
version: '0.8.0'
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup tools (vx)
run: vx setup
- name: Add Rust components
run: vx rustup component add clippy rustfmt
- name: Setup MSVC Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1
- name: Fix MSVC linker (remove Git's link.exe)
run: Remove-Item 'C:\Program Files\Git\usr\bin\link.exe' -Force -ErrorAction SilentlyContinue
shell: pwsh
- name: Cache cargo
uses: Swatinem/rust-cache@v2
with:
shared-key: release-x64
- name: Build release binary
run: vx just build-release-locked
- name: Rename binary
shell: pwsh
run: |
Copy-Item "target/release/msvc-kit.exe" "msvc-kit-x86_64-windows.exe"
- name: Upload binary artifact
uses: actions/upload-artifact@v6
with:
name: msvc-kit-x86_64-windows
path: msvc-kit-x86_64-windows.exe
if-no-files-found: error
github-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs:
[
release-please,
check-tag,
crates-publish,
build-release-binary,
]
if: |
always() &&
((needs.release-please.result == 'success' && needs.release-please.outputs.release_created == 'true') ||
(needs.check-tag.result == 'success' && needs.check-tag.outputs.is_tag == 'true')) &&
needs.build-release-binary.result == 'success'
permissions:
contents: write
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Determine tag name
id: tag
run: |
if [ "${{ needs.release-please.outputs.tag_name }}" != "" ]; then
echo "TAG_NAME=${{ needs.release-please.outputs.tag_name }}" >> $GITHUB_OUTPUT
else
echo "TAG_NAME=${{ needs.check-tag.outputs.tag_name }}" >> $GITHUB_OUTPUT
fi
- name: Determine version
id: version
run: |
TAG="${{ steps.tag.outputs.TAG_NAME }}"
echo "VERSION=${TAG#v}" >> $GITHUB_OUTPUT
- name: Download release binary
uses: actions/download-artifact@v6
with:
name: msvc-kit-x86_64-windows
path: artifacts/
- name: Prepare release asset
run: |
mv artifacts/msvc-kit-x86_64-windows/msvc-kit-x86_64-windows.exe ./msvc-kit-x86_64-windows.exe
- name: Generate changelog
id: changelog
uses: jaywcjlove/changelog-generator@main
with:
token: ${{ secrets.GITHUB_TOKEN }}
filter-author: (loonghao|renovate\[bot\]|dependabot\[bot\]|Renovate Bot)
filter: ""
template: |
## Bugs
{{fix}}
## Feature
{{feat}}
## Improve
{{refactor,perf,clean}}
## Misc
{{chore,style,ci,build||🔧 Nothing changed}}
## Unknown
{{__unknown__}}
- name: Create GitHub Release
uses: ncipollo/release-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ steps.tag.outputs.TAG_NAME }}
name: ${{ steps.tag.outputs.TAG_NAME }}
body: |
Comparing Changes: ${{ steps.changelog.outputs.compareurl }}
${{ steps.changelog.outputs.changelog }}
---
### Installation
**Cargo:**
```bash
cargo install msvc-kit
```
**WinGet:**
```bash
winget install loonghao.msvc-kit
```
**Direct Download (Windows x64):**
- [msvc-kit-x86_64-windows.exe](https://github.com/loonghao/msvc-kit/releases/download/${{ steps.tag.outputs.TAG_NAME }}/msvc-kit-x86_64-windows.exe)
artifacts: msvc-kit-x86_64-windows.exe
draft: false
prerelease: false
allowUpdates: true
skipIfReleaseExists: false
updateOnlyUnreleased: false
makeLatest: true
update-winget:
name: Update WinGet
runs-on: ubuntu-latest
needs: [release-please, check-tag, github-release]
if: |
always() &&
needs.github-release.result == 'success'
steps:
- uses: actions/checkout@v6
- name: Determine version and tag
id: version
run: |
if [ "${{ needs.release-please.outputs.version }}" != "" ]; then
echo "VERSION=${{ needs.release-please.outputs.version }}" >> $GITHUB_OUTPUT
echo "TAG_NAME=${{ needs.release-please.outputs.tag_name }}" >> $GITHUB_OUTPUT
else
echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT
echo "TAG_NAME=${{ needs.check-tag.outputs.tag_name }}" >> $GITHUB_OUTPUT
fi
- name: Wait for release assets to be available
run: |
echo "Waiting for release assets to be fully available..."
sleep 30
- name: Update WinGet manifest
uses: vedantmgoyal2009/winget-releaser@v2
with:
identifier: loonghao.msvc-kit
installers-regex: '^msvc-kit-x86_64-windows\.exe$'
version: ${{ steps.version.outputs.VERSION }}
release-tag: ${{ steps.version.outputs.TAG_NAME }}
token: ${{ secrets.WINGET_TOKEN }}
continue-on-error: true