Files
cursor-lang/.gitea/workflows/release.yml
T
alex 6259dbd6b3
Pull request / build (pull_request) Successful in 53s
lightweight variant
2026-08-12 16:01:54 +05:00

167 lines
7.1 KiB
YAML

# The release: a tag of the form v1.2.3 builds the solution, runs the tests and
# packs the MSIX with the version taken from the tag — three numbers of the tag
# and a zero the Store keeps for itself.
#
# The same requirements to the runner as in pull-request.yml apply: Windows, the
# .NET 10 SDK and an interactive desktop session for the tests. makeappx comes
# with a NuGet package (Packaging\Tools\SdkTools.csproj), so the Windows SDK does
# not have to be installed.
name: Release
on:
push:
tags:
- 'v*'
defaults:
run:
shell: pwsh
jobs:
release:
runs-on: windows-x64
steps:
- name: Check out the sources
uses: actions/checkout@v4
# The exe icon and the MSIX logos live in Git LFS, and without them the
# checkout leaves text pointers in their place — the build fails on the
# icon and the package would carry broken logos.
#
# They are fetched here rather than by `lfs: true` on the checkout: that
# way the objects arrive over a request the LFS endpoint accepts. See the
# comment on the header below
- name: Fetch the LFS objects
run: |
$ErrorActionPreference = 'Stop'
# actions/checkout leaves its own token in the config as an
# http.<server>/.extraheader, and git-lfs sends that header on to the
# LFS endpoint, which turns down the token of a workflow: every object
# comes back 401 and the fetch gives up. The repository is public and
# its LFS objects are readable without a token at all, so the header
# simply goes. A private repository would need credentials of its own
# in lfs.url instead
$keys = git config --local --list --name-only | Where-Object { $_ -like '*.extraheader' }
foreach ($key in $keys) { git config --local --unset-all $key }
git lfs pull
if ($LASTEXITCODE -ne 0) { throw "git lfs pull ended with exit code $LASTEXITCODE." }
# A pointer left in place of a file shows itself much later and in a
# way that is hard to read back: the icon breaks the build, and a logo
# quietly ends up broken inside the package
$pointers = git lfs ls-files --name-only |
Where-Object { (Get-Content $_ -TotalCount 1) -like 'version https://git-lfs*' }
if ($pointers) {
throw "Git LFS left pointers instead of files: $($pointers -join ', ')."
}
# The tag is the only place the version comes from, and it is a plain
# version of three numbers — the same shape the application itself looks
# for in the releases when it checks for an update. A tag of any other
# shape is stopped here rather than halfway through the packaging
- name: Read the version from the tag
id: version
run: |
$ErrorActionPreference = 'Stop'
$tag = '${{ github.ref_name }}'
if ($tag -notmatch '^v\d+\.\d+\.\d+$') {
throw "The tag '$tag' does not fit: a release is tagged as v1.2.3 — three numbers. A fourth one does not belong in the tag: the Store keeps the revision for itself, and the package always gets a zero there."
}
# The package takes four numbers with a zero at the end: the Store
# reserves the last one, so it carries nothing the tag could tell
"version=$($tag.Substring(1)).0" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8
- name: Show the toolchain
run: dotnet --info
- name: Restore
run: dotnet restore CursorLang.sln --nologo
- name: Build
run: dotnet build CursorLang.sln --configuration Release --no-restore --nologo
- name: Test
run: >
dotnet test CursorLang.sln
--configuration Release
--no-build
--nologo
--settings coverage.runsettings
# The package comes out as Partner Center wants it — the Store puts its own
# signature on it. The identity comes from repository variables and falls
# back to the defaults of the script when a variable is not set.
- name: Pack the MSIX
env:
IDENTITY_NAME: ${{ vars.MSIX_IDENTITY_NAME }}
PUBLISHER: ${{ vars.MSIX_PUBLISHER }}
PUBLISHER_DISPLAY_NAME: ${{ vars.MSIX_PUBLISHER_DISPLAY_NAME }}
run: |
$ErrorActionPreference = 'Stop'
$arguments = @{ Version = '${{ steps.version.outputs.version }}' }
# An empty variable is left out rather than passed on: the script has
# defaults of its own, and an empty string would wipe them
$variables = @{
IdentityName = $env:IDENTITY_NAME
Publisher = $env:PUBLISHER
PublisherDisplayName = $env:PUBLISHER_DISPLAY_NAME
}
foreach ($name in $variables.Keys) {
if ($variables[$name]) { $arguments[$name] = $variables[$name] }
}
./Packaging/build-msix.ps1 @arguments
- name: Keep the packages
uses: actions/upload-artifact@v4
with:
name: msix-${{ steps.version.outputs.version }}
path: artifacts/packages/
if-no-files-found: error
# Gitea creates a release of its own for a pushed tag, so the release is
# looked up first and only made when it is not there
- name: Publish the release
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
TAG: ${{ github.ref_name }}
run: |
$ErrorActionPreference = 'Stop'
# The GITHUB_ names are what Gitea itself hands to the workflow — its
# actions repeat those of GitHub, and the addresses in them point at
# this Gitea instance. GITHUB_API_URL used not to reach the steps at
# all, so the address is put together from the server one when empty
$root = if ($env:GITHUB_API_URL) { $env:GITHUB_API_URL } else { "$env:GITHUB_SERVER_URL/api/v1" }
$api = "$root/repos/$env:GITHUB_REPOSITORY/releases"
$headers = @{ Authorization = "token $env:GITEA_TOKEN" }
$release = $null
try { $release = Invoke-RestMethod "$api/tags/$env:TAG" -Headers $headers } catch { }
if (-not $release) {
$body = @{ tag_name = $env:TAG; name = $env:TAG; draft = $false; prerelease = $false } | ConvertTo-Json
$release = Invoke-RestMethod $api -Method Post -Headers $headers -ContentType 'application/json' -Body $body
}
foreach ($file in Get-ChildItem artifacts/packages -File) {
# A tag can be pushed again after it was deleted; the old file of
# the same name is dropped, otherwise the upload is refused
$existing = $release.assets | Where-Object { $_.name -eq $file.Name }
foreach ($asset in $existing) {
Invoke-RestMethod "$api/$($release.id)/assets/$($asset.id)" -Method Delete -Headers $headers | Out-Null
}
Write-Host "Uploading $($file.Name)"
Invoke-RestMethod "$api/$($release.id)/assets?name=$($file.Name)" -Method Post -Headers $headers -Form @{ attachment = $file } | Out-Null
}