feat: preserve tool calls across protocol bridges and download deskto… #28
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
| name: release-switcher | |
| # Core CLI release only (GoReleaser, R2 CLI, npm, winget) — v* tags or manual dispatch. | |
| # Desktop shell: release-desktop.yml | Landing site: deploy-landing.yml | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Release version without leading v (for npm/winget only)" | |
| required: false | |
| type: string | |
| permissions: | |
| contents: write | |
| env: | |
| R2_PUBLIC_BASE_URL: https://downloads.clovapi.com | |
| jobs: | |
| goreleaser: | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: core | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check existing CLI release | |
| id: existing_cli_release | |
| working-directory: . | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| echo "complete=false" >> "$GITHUB_OUTPUT" | |
| if [[ "${GITHUB_REF_NAME:-}" != v* ]]; then | |
| exit 0 | |
| fi | |
| version="${GITHUB_REF_NAME#v}" | |
| required_assets=( | |
| "checksums.txt" | |
| "clovapi_${version}_darwin_amd64.tar.gz" | |
| "clovapi_${version}_darwin_arm64.tar.gz" | |
| "clovapi_${version}_linux_amd64.tar.gz" | |
| "clovapi_${version}_linux_arm64.tar.gz" | |
| "clovapi_${version}_windows_amd64.zip" | |
| "clovapi_${version}_windows_arm64.zip" | |
| ) | |
| if ! gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --json assets > /tmp/clovapi-release.json 2>/dev/null; then | |
| exit 0 | |
| fi | |
| for asset in "${required_assets[@]}"; do | |
| if ! jq -e --arg name "$asset" '.assets | any(.name == $name)' /tmp/clovapi-release.json >/dev/null; then | |
| exit 0 | |
| fi | |
| done | |
| echo "complete=true" >> "$GITHUB_OUTPUT" | |
| echo "Release $GITHUB_REF_NAME already has all CLI assets; skipping GoReleaser publish." | |
| - name: Setup Go | |
| if: steps.existing_cli_release.outputs.complete != 'true' | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: core/go.mod | |
| - name: Run tests | |
| if: steps.existing_cli_release.outputs.complete != 'true' | |
| run: go test ./... | |
| - name: Setup GoReleaser | |
| if: steps.existing_cli_release.outputs.complete != 'true' | |
| uses: goreleaser/goreleaser-action@v6 | |
| with: | |
| version: "~> v2" | |
| install-only: true | |
| - name: GoReleaser release | |
| if: steps.existing_cli_release.outputs.complete != 'true' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }} | |
| run: | | |
| if [ -n "$HOMEBREW_TAP_GITHUB_TOKEN" ]; then | |
| goreleaser release --clean --config .goreleaser.yaml | |
| else | |
| goreleaser release --clean --config .goreleaser.yaml --skip=homebrew | |
| fi | |
| - name: Decide R2 publish | |
| id: r2_gate | |
| if: steps.existing_cli_release.outputs.complete != 'true' | |
| working-directory: . | |
| run: | | |
| if [ -n "${{ secrets.R2_ACCOUNT_ID }}" ] && [ -n "${{ secrets.R2_ACCESS_KEY_ID }}" ] && [ -n "${{ secrets.R2_SECRET_ACCESS_KEY }}" ] && [ -n "${{ secrets.R2_BUCKET }}" ]; then | |
| echo "publish=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "publish=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Resolve release tag | |
| id: release_tag | |
| if: ${{ steps.r2_gate.outputs.publish == 'true' }} | |
| working-directory: . | |
| env: | |
| RELEASE_INPUT_VERSION: ${{ github.event.inputs.version }} | |
| run: | | |
| set -euo pipefail | |
| if [[ "${GITHUB_REF_NAME:-}" == v* ]]; then | |
| echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" | |
| elif [[ -n "${RELEASE_INPUT_VERSION:-}" ]]; then | |
| echo "tag=v${RELEASE_INPUT_VERSION}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "tag=" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Setup Python | |
| if: ${{ steps.r2_gate.outputs.publish == 'true' && steps.release_tag.outputs.tag != '' }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.x" | |
| - name: Install awscli | |
| if: ${{ steps.r2_gate.outputs.publish == 'true' && steps.release_tag.outputs.tag != '' }} | |
| run: pip install --upgrade awscli | |
| - name: Upload CLI artifacts to Cloudflare R2 | |
| if: ${{ steps.r2_gate.outputs.publish == 'true' && steps.release_tag.outputs.tag != '' }} | |
| working-directory: . | |
| env: | |
| R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }} | |
| R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} | |
| R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} | |
| R2_SESSION_TOKEN: ${{ secrets.R2_SESSION_TOKEN }} | |
| R2_BUCKET: ${{ secrets.R2_BUCKET }} | |
| R2_ARTIFACT_PREFIX: ${{ secrets.R2_ARTIFACT_PREFIX }} | |
| run: | | |
| set -euo pipefail | |
| chmod +x scripts/r2-publish.sh | |
| ./scripts/r2-publish.sh cli --tag "${{ steps.release_tag.outputs.tag }}" --dist core/dist | |
| ./scripts/r2-publish.sh install-sh --file landing/public/install.sh | |
| npm: | |
| runs-on: ubuntu-latest | |
| needs: goreleaser | |
| if: ${{ startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Decide npm publish | |
| id: npm_gate | |
| working-directory: . | |
| env: | |
| NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| run: | | |
| if [ -n "$NPM_TOKEN" ]; then | |
| echo "publish=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "publish=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Setup Node | |
| if: ${{ steps.npm_gate.outputs.publish == 'true' }} | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| registry-url: "https://registry.npmjs.org" | |
| - name: Sync package version from tag | |
| if: ${{ steps.npm_gate.outputs.publish == 'true' && startsWith(github.ref, 'refs/tags/v') }} | |
| working-directory: npm | |
| run: | | |
| target_version="${GITHUB_REF_NAME#v}" | |
| current_version="$(node -p "require('./package.json').version")" | |
| if [ "$current_version" != "$target_version" ]; then | |
| npm version "$target_version" --no-git-tag-version | |
| else | |
| echo "package.json version already $target_version, skip npm version" | |
| fi | |
| - name: Sync package version from input | |
| if: ${{ steps.npm_gate.outputs.publish == 'true' && github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' }} | |
| working-directory: npm | |
| run: | | |
| target_version="${{ github.event.inputs.version }}" | |
| current_version="$(node -p "require('./package.json').version")" | |
| if [ "$current_version" != "$target_version" ]; then | |
| npm version "$target_version" --no-git-tag-version | |
| else | |
| echo "package.json version already $target_version, skip npm version" | |
| fi | |
| - name: Check published npm version | |
| id: npm_version | |
| if: ${{ steps.npm_gate.outputs.publish == 'true' }} | |
| working-directory: npm | |
| run: | | |
| version="$(node -p "require('./package.json').version")" | |
| if npm view "@clovapi/cli@${version}" version >/dev/null 2>&1; then | |
| echo "exists=true" >> "$GITHUB_OUTPUT" | |
| echo "@clovapi/cli ${version} is already published; skipping npm publish." | |
| else | |
| echo "exists=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Publish npm package | |
| if: ${{ steps.npm_gate.outputs.publish == 'true' && steps.npm_version.outputs.exists != 'true' }} | |
| working-directory: npm | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| run: npm publish --access public | |
| winget: | |
| runs-on: windows-latest | |
| needs: goreleaser | |
| if: ${{ startsWith(github.ref, 'refs/tags/v') }} | |
| defaults: | |
| run: | |
| shell: pwsh | |
| steps: | |
| - name: Decide winget submit | |
| id: winget_gate | |
| working-directory: . | |
| run: | | |
| if ([string]::IsNullOrWhiteSpace("${{ secrets.WINGET_CREATE_TOKEN }}")) { | |
| Write-Host "WINGET_CREATE_TOKEN is empty, skip winget submit." | |
| "submit=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append | |
| exit 0 | |
| } | |
| $manifestPath = "manifests/c/Clovapi/Clovapi" | |
| $manifestApi = "https://api.github.com/repos/microsoft/winget-pkgs/contents/$manifestPath" | |
| $headers = @{ | |
| "Accept" = "application/vnd.github+json" | |
| "User-Agent" = "clovapi-release-workflow" | |
| } | |
| try { | |
| Invoke-RestMethod -Uri $manifestApi -Headers $headers -Method Get | Out-Null | |
| Write-Host "Found winget package path '$manifestPath', will submit update." | |
| "submit=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append | |
| } catch { | |
| $statusCode = $null | |
| if ($_.Exception.Response -and $_.Exception.Response.StatusCode) { | |
| $statusCode = [int]$_.Exception.Response.StatusCode | |
| } | |
| if ($statusCode -eq 404) { | |
| Write-Warning "winget package path '$manifestPath' not found in microsoft/winget-pkgs. Skip automated update until first manifest PR is merged." | |
| "submit=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append | |
| } else { | |
| throw | |
| } | |
| } | |
| - name: Checkout | |
| if: ${{ steps.winget_gate.outputs.submit == 'true' }} | |
| uses: actions/checkout@v4 | |
| - name: Install wingetcreate | |
| if: ${{ steps.winget_gate.outputs.submit == 'true' }} | |
| run: winget install --id Microsoft.WingetCreate --source winget --accept-source-agreements --accept-package-agreements | |
| - name: Submit winget update PR | |
| if: ${{ steps.winget_gate.outputs.submit == 'true' }} | |
| env: | |
| WINGET_CREATE_TOKEN: ${{ secrets.WINGET_CREATE_TOKEN }} | |
| run: | | |
| $version = "${env:GITHUB_REF_NAME}".TrimStart("v") | |
| wingetcreate update Clovapi.Clovapi --version $version --submit --token $env:WINGET_CREATE_TOKEN |