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.
112 lines
3.9 KiB
PowerShell
112 lines
3.9 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Links the extension sources into VS Code's extensions folder for development.
|
|
|
|
.DESCRIPTION
|
|
Packaging is the wrong loop while you are actually changing code. VS Code loads any
|
|
folder under %USERPROFILE%\.vscode\extensions that has a package.json, so linking the
|
|
source there reduces the edit cycle to "npm run compile" plus a window reload.
|
|
|
|
The link is a directory junction rather than a symlink because junctions need no
|
|
elevation and no Developer Mode on Windows, and VS Code cannot tell the difference.
|
|
|
|
Run -Unlink before install.ps1: a linked source and an installed .vsix are two copies
|
|
of the same extension id, and VS Code will load one of them arbitrarily.
|
|
|
|
.PARAMETER Only
|
|
Restrict to these extension ids.
|
|
|
|
.PARAMETER Unlink
|
|
Remove the links.
|
|
|
|
.PARAMETER Compile
|
|
Run npm run compile in each extension first.
|
|
|
|
.EXAMPLE
|
|
.\scripts\dev-link.ps1 -Compile
|
|
.\scripts\dev-link.ps1 -Unlink
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[string[]] $Only,
|
|
[switch] $Unlink,
|
|
[switch] $Compile
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
. (Join-Path $PSScriptRoot 'common.ps1')
|
|
|
|
$config = Get-SetupConfig
|
|
$extensionsDir = Join-Path $env:USERPROFILE '.vscode\extensions'
|
|
if (-not (Test-Path $extensionsDir)) {
|
|
New-Item -ItemType Directory -Path $extensionsDir -Force | Out-Null
|
|
}
|
|
|
|
$extensions = $config.extensions
|
|
if ($Only) {
|
|
$extensions = $extensions | Where-Object { $Only -contains $_.id }
|
|
$missing = $Only | Where-Object { $config.extensions.id -notcontains $_ }
|
|
if ($missing) { throw "not in config.json: $($missing -join ', ')" }
|
|
}
|
|
|
|
foreach ($extension in $extensions) {
|
|
$source = Get-ExtensionPath $extension
|
|
$manifestPath = Join-Path $source 'package.json'
|
|
if (-not (Test-Path $manifestPath)) {
|
|
Write-Warning "no package.json in $source, skipping $($extension.id)"
|
|
continue
|
|
}
|
|
$manifest = Get-Content $manifestPath -Raw | ConvertFrom-Json
|
|
$linkName = "$($manifest.publisher).$($manifest.name)-$($manifest.version)"
|
|
$link = Join-Path $extensionsDir $linkName
|
|
|
|
if ($Unlink) {
|
|
if (Test-Path $link) {
|
|
# Remove-Item on a junction deletes the link, not the target -- but only
|
|
# without -Recurse, which would walk into the source and delete the files.
|
|
[System.IO.Directory]::Delete($link)
|
|
Write-Host "unlinked $linkName" -ForegroundColor Green
|
|
} else {
|
|
Write-Host "$linkName was not linked" -ForegroundColor DarkGray
|
|
}
|
|
continue
|
|
}
|
|
|
|
if ($Compile) {
|
|
Push-Location $source
|
|
try {
|
|
Write-Host "compiling $($extension.id)..." -ForegroundColor DarkGray
|
|
if (-not (Test-Path (Join-Path $source 'node_modules'))) {
|
|
& npm install --silent --no-audit --no-fund
|
|
if ($LASTEXITCODE -ne 0) { throw "npm install failed for $($extension.id)" }
|
|
}
|
|
& npm run compile --silent
|
|
if ($LASTEXITCODE -ne 0) { throw "compile failed for $($extension.id)" }
|
|
} finally { Pop-Location }
|
|
}
|
|
|
|
$main = $manifest.main -replace '^\./', ''
|
|
if (-not (Test-Path (Join-Path $source $main))) {
|
|
Write-Warning ("$($extension.id) has no built output at $main -- it will fail to " +
|
|
"activate. Pass -Compile.")
|
|
}
|
|
|
|
if (Test-Path $link) {
|
|
$item = Get-Item $link -Force
|
|
$target = $item.Target
|
|
if ($target -and @($target)[0] -eq $source) {
|
|
Write-Host "$linkName already linked" -ForegroundColor DarkGray
|
|
continue
|
|
}
|
|
throw ("$link already exists and does not point at $source. Remove it by hand " +
|
|
"(it may be a real installed copy).")
|
|
}
|
|
|
|
New-Item -ItemType Junction -Path $link -Target $source | Out-Null
|
|
Write-Host "linked $linkName -> $source" -ForegroundColor Green
|
|
}
|
|
|
|
Write-Host ''
|
|
Write-Host 'Reload the window (Developer: Reload Window) to pick this up.' -ForegroundColor Cyan
|