Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions .github/workflows/preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Hand-written (not auto-generated). The "preview" channel — per-commit builds of main.
#
# Counterpart to the framework repo's publish-packages-preview.yml, which pushes a
# -preview prerelease to GitHub Packages on every commit to main. The extension can't
# do the same thing: GitHub Packages does not speak the VS Code gallery protocol, and
# neither marketplace accepts a semver prerelease version. So the preview channel here
# is a ROLLING GitHub pre-release whose asset is replaced on every push.
#
# Why a rolling release rather than workflow artifacts:
# - the download URL is stable, so installing is one command with no run-hunting:
#
# gh release download preview -R Fallout-build/Fallout.Extensions.VSCode -p '*.vsix' --clobber
# code --install-extension fallout.vsix
#
# or, from a clone: dotnet fallout InstallVsix
# - workflow artifacts expire and need the run ID to fetch.
#
# The tag is `preview`, deliberately NOT matching `v*`. Two consequences, both wanted:
# publish.yml (which triggers on v* only) does not fire, and the v* tag-protection
# ruleset does not apply to a tag this workflow force-moves on every push.
#
# The .vsix is marked as a marketplace pre-release, so if it is ever sideloaded next to
# a stable build VS Code shows it as pre-release rather than silently as a release.
#
# NOTE: this publishes NOTHING to any marketplace. It is the GitHub pre-stage only.
name: preview

on:
push:
branches:
- main
paths-ignore:
- '**/*.md'
workflow_dispatch:

permissions:
contents: read

concurrency:
# Never cancel in progress: a cancelled run could leave the rolling release holding a
# half-uploaded asset. Queue instead, so the newest push wins by finishing last.
group: preview
cancel-in-progress: false

jobs:
preview:
name: preview
runs-on: ubuntu-latest
permissions:
contents: write
environment:
name: github-releases
url: https://github.com/Fallout-build/Fallout.Extensions.VSCode/releases/tag/preview
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # Nerdbank.GitVersioning needs full history
- uses: actions/setup-node@v6
with:
node-version: 20
cache: npm
- uses: actions/setup-dotnet@v6
with:
global-json-file: global.json

# PublicRelease: main IS in version.json's publicReleaseRefSpec, so this is only
# belt-and-braces for the workflow_dispatch case on a detached checkout.
- name: 'Fallout build (PackVsix)'
run: ./build.sh PackVsix
env:
PreRelease: true
PublicRelease: true

# Per-run copy, alongside the rolling release asset below. The release is the thing
# you install from; this is the fixed record of what a specific commit produced,
# which the rolling asset can't be since it is replaced on the next push.
- uses: actions/upload-artifact@v7
with:
name: fallout-vsix
path: fallout.vsix
retention-days: 14
if-no-files-found: error

- name: 'Read the packaged version'
id: version
run: |
set -euo pipefail
# Take it from the VSIX manifest rather than recomputing — this reports what was
# actually built, so a version bug shows up here instead of being masked.
#
# Scoped to the <Identity> element on purpose: the FIRST Version= attribute in the
# manifest is <PackageManifest Version="2.0.0">, the manifest schema version, so a
# naive "first match" reports 2.0.0 for every build.
unzip -p fallout.vsix extension.vsixmanifest > manifest.xml
VERSION=$(grep -o '<Identity[^>]*' manifest.xml | grep -o 'Version="[^"]*"' | cut -d'"' -f2)
if [ -z "$VERSION" ]; then
echo "::error::Could not read the version from the VSIX manifest."
exit 1
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Packaged version: $VERSION"

- name: 'Update the rolling preview release'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail

NOTES=$(cat <<EOF
Rolling preview build of \`main\` — **replaced on every push**, so this release is not a
durable reference. For a fixed version, use a tagged release instead.

| | |
|---|---|
| Version | \`$VERSION\` |
| Commit | ${GITHUB_SHA:0:7} |
| Built | $(date -u '+%Y-%m-%d %H:%M UTC') |

Not published to any marketplace. Install with:

\`\`\`bash
gh release download preview -R ${GITHUB_REPOSITORY} -p '*.vsix' --clobber
code --install-extension fallout.vsix --force
\`\`\`

Installing is manual by design — VS Code only auto-updates extensions it got from a
gallery, and there is no gallery in this channel. See RELEASING.md.
EOF
)

# Move the tag to this commit. The release keeps its identity; only the target
# and asset change, so the download URL stays valid.
git tag -f preview
git push -f origin refs/tags/preview

if gh release view preview > /dev/null 2>&1; then
gh release edit preview --target "$GITHUB_SHA" --notes "$NOTES" --prerelease
gh release upload preview fallout.vsix --clobber
else
gh release create preview \
--title 'Preview (rolling)' \
--target "$GITHUB_SHA" \
--notes "$NOTES" \
--prerelease \
fallout.vsix
fi
27 changes: 27 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,39 @@ GitHub is the pre-stage; each marketplace is a promotion target with its own env

| Channel | Trigger | Gating |
|---|---|---|
| `preview` (rolling) | every push to `main` | none |
| `github-releases` | any release tag | none |
| `vs-marketplace` | `workflow_dispatch` opt-in flag | flag + approval |
| `open-vsx` | `workflow_dispatch` opt-in flag | flag + approval |

A tag push **never** reaches a marketplace. Promotion is deliberate: set the flag, then approve the environment — two independent layers, matching how Fallout gates nuget.org.

## The preview channel

Every push to `main` builds a `.vsix` and replaces the asset on a rolling `preview` GitHub pre-release (`preview.yml`). It's the counterpart to the framework's per-commit `-preview` packages — reshaped because GitHub Packages doesn't speak the VS Code gallery protocol and neither marketplace accepts a semver prerelease.

The `preview` tag deliberately doesn't match `v*`, so it neither triggers `publish.yml` nor falls under the `v*` tag-protection ruleset — which matters, because the workflow force-moves it on every push.

### Installing a preview

```bash
gh release download preview -R Fallout-build/Fallout.Extensions.VSCode -p '*.vsix' --clobber
code --install-extension fallout.vsix --force
```

The download URL is stable, so that pair of commands is the whole update story — no run IDs to hunt, no expiry. Each run also uploads the same `.vsix` as a workflow artifact, which is the fixed record of what a given commit produced; the rolling asset can't be, since the next push replaces it.

Building locally, `dotnet fallout PackVsix` produces the `.vsix` and you install it the same way. Installing is deliberately a manual step — the build never touches your editor.

### Why this isn't auto-updating

VS Code will not auto-update a manually installed extension — it only tracks versions for extensions it got from a gallery, and this channel has no gallery. Manual download-and-install is the deliberate trade-off; the build never touches your editor.

Two ways to get real automatic updates, if that ever becomes worth the cost:

- **Marketplace pre-release channel.** The native mechanism: VS Code offers *"Switch to Pre-Release Version"* and updates it like anything else. Requires an actual marketplace presence. Note the version-burning concern doesn't apply to a preview stream — the patch is a git height, so every build has a unique number and stable is always a later height.
- **A self-hosted gallery at `gallery.fallout.build`** — tracked as [#6](https://github.com/Fallout-build/Fallout.Extensions.VSCode/issues/6), with hosting options and trade-offs in [Chrison-Homelab/Homelab#409](https://github.com/Chrison-Homelab/Homelab/issues/409). Candidates are Microsoft's own [Private Marketplace](https://github.com/microsoft/vsmarketplace/blob/main/privatemarketplace/latest/README.md) (stateless container, configured by supported device-management policy, but every consumer needs a Copilot Business/Enterprise seat), `coder/code-marketplace`, or self-hosted Open VSX. Since registries are already modelled as data in `IPublishVsix`, adding one is a target entry rather than a new pipeline.

## Cutting a release candidate

```bash
Expand Down
1 change: 1 addition & 0 deletions plugins/Fallout.Vsce/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ dotnet fallout PublishVsix --publish-vsix-to open-vsx
- **`ovsx` ignores `--pre-release` for a prepackaged `.vsix`** — it reads the manifest. Package it correctly; don't rely on the publish flag.
- **`vsce publish --pre-release` on a `--packagePath` is only an assertion** against the package, not what sets the status.
- **Tool resolution** prefers `node_modules/.bin` over `PATH`, since both CLIs are conventionally dev dependencies. Override via `IHasVsix.VsceToolPath` / `OvsxToolPath`.
- **Installing is out of scope on purpose.** This plugin packages and publishes; it does not touch the local editor. A manually installed `.vsix` never auto-updates anyway, since VS Code only tracks versions for extensions it got from a gallery.
- **Tokens** are left to the CLIs' own environment variables (`VSCE_PAT`, `OVSX_PAT`) unless you set `VsixPublishTarget.Pat`, so they stay out of process argument lists.

## Status
Expand Down
Loading