Files
vs-code-setup/scripts/publish.ps1
T
max d45639bf2f Build, publish to Gitea releases, and install the three extensions
Answers two things: how to install these without a marketplace, and how to keep
settings in sync when VS Code's Settings Sync cannot be pointed at Gitea.

- build.ps1 packages each extension into dist/
- publish.ps1 creates a release and uploads them, replacing same-named assets so a
  rolling "latest" tag stays clean
- install.ps1 downloads a release's assets and installs them, or -Local from dist/
- settings.ps1 copies User/ between the repo and the machine, and installs the
  marketplace extensions recorded in extensions.txt
- dev-link.ps1 junctions the sources into ~/.vscode/extensions for development
- ci-release.sh plus a Gitea Actions workflow do the build and publish on a tag push

Settings are copied, not symlinked: an atomic save replaces a symlink with a regular
file and the sync stops without looking broken.

vsce/ pins vsce and undici so packaging works on Node 18, which current vsce does not
support.

test/run.ps1 drives the real scripts against a stub of the Gitea release API. It
caught the multipart Content-Disposition being unquoted on .NET Framework, and
Invoke-WebRequest dropping the Authorization header across a redirect.
2026-09-07 19:35:20 +02:00

113 lines
3.8 KiB
PowerShell

<#
.SYNOPSIS
Uploads dist/*.vsix to a release on Gitea.
.DESCRIPTION
Creates the release for -Tag if it does not exist, then uploads each .vsix as an
asset. An asset with the same name is deleted first, so re-publishing the same tag
replaces the packages instead of piling up duplicates -- which is what makes the
default rolling "latest" tag usable as the thing install.ps1 reads.
Needs a token with write:repository scope. See Get-GiteaToken in common.ps1 for
where it is read from; it is never read from inside this repo.
.PARAMETER Tag
The release tag. Defaults to "latest", a rolling release holding current builds.
Use a version tag for a snapshot you want to keep.
.PARAMETER Build
Run build.ps1 first.
.PARAMETER Notes
Release body. Defaults to a list of the packages and their versions.
.EXAMPLE
.\scripts\publish.ps1 -Build
.\scripts\publish.ps1 -Tag v0.1.0 -Notes 'First cut of all three.'
#>
[CmdletBinding()]
param(
[string] $Tag = 'latest',
[string] $Token,
[string] $Notes,
[string] $Target,
[switch] $Build,
[switch] $Prerelease
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'common.ps1')
if ($Build) { & (Join-Path $PSScriptRoot 'build.ps1') | Out-Null }
$config = Get-SetupConfig
$Token = Get-GiteaToken -Token $Token
$dist = Get-DistDir
$repoPath = "/repos/$($config.gitea.owner)/$($config.gitea.repo)"
$packages = @(Get-ChildItem -Path $dist -Filter '*.vsix' | Sort-Object Name)
if ($packages.Count -eq 0) {
throw "no .vsix files in $dist. Run build.ps1, or pass -Build."
}
Write-Host "publishing $($packages.Count) package(s) to " -NoNewline
Write-Host "$($config.gitea.url)/$($config.gitea.owner)/$($config.gitea.repo)@$Tag" -ForegroundColor Cyan
$release = Get-GiteaRelease -Tag $Tag -Token $Token
if ($release) {
Write-Host "reusing release $($release.id)" -ForegroundColor DarkGray
} else {
if (-not $Notes) {
$lines = $packages | ForEach-Object {
$name = $_.BaseName
"- $name"
}
$Notes = @(
'VS Code extensions, packaged as VSIX.',
'',
($lines -join "`n"),
'',
'Install them with scripts/install.ps1, or by hand:',
'',
' code --install-extension <file>.vsix --force'
) -join "`n"
}
$body = @{
tag_name = $Tag
name = "VS Code extensions ($Tag)"
body = $Notes
draft = $false
prerelease = [bool] $Prerelease
}
# Omitted means Gitea creates the tag on the default branch.
if ($Target) { $body.target_commitish = $Target }
$release = Invoke-Gitea -Token $Token -Method 'POST' -Path "$repoPath/releases" -Body $body
Write-Host "created release $($release.id) for tag $Tag" -ForegroundColor DarkGray
}
$existing = @()
if ($release.PSObject.Properties.Name -contains 'assets' -and $release.assets) {
$existing = @($release.assets)
}
foreach ($package in $packages) {
$clash = $existing | Where-Object { $_.name -eq $package.Name }
foreach ($old in $clash) {
Write-Host " replacing $($package.Name)" -ForegroundColor DarkGray
Invoke-Gitea -Token $Token -Method 'DELETE' `
-Path "$repoPath/releases/$($release.id)/assets/$($old.id)" | Out-Null
}
$size = [math]::Round($package.Length / 1KB, 1)
Write-Host " uploading $($package.Name) ($size KB)" -NoNewline
$asset = Send-GiteaAsset -ReleaseId $release.id -FilePath $package.FullName -Token $Token
Write-Host " ok" -ForegroundColor Green
Write-Verbose " $($asset.browser_download_url)"
}
Write-Host ''
Write-Host "done: $($config.gitea.url)/$($config.gitea.owner)/$($config.gitea.repo)/releases/tag/$Tag" -ForegroundColor Cyan