Skip to content

Commit e669fcd

Browse files
fix(vscode): publish the extension under the aet-tum publisher (#812)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 610cde8 commit e669fcd

9 files changed

Lines changed: 95 additions & 35 deletions

File tree

.github/workflows/release-vscode-extension.yml

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727
contents: read
2828
outputs:
2929
version: ${{ steps.v.outputs.version }}
30+
publisher: ${{ steps.v.outputs.publisher }}
31+
name: ${{ steps.v.outputs.name }}
32+
extension-id: ${{ steps.v.outputs.extension-id }}
3033
publish: ${{ steps.v.outputs.publish }}
3134
release: ${{ steps.v.outputs.release }}
3235
steps:
@@ -49,6 +52,18 @@ jobs:
4952
fi
5053
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
5154
55+
# The manifest is the only source for the Marketplace identity: `vsce`
56+
# and `ovsx` derive what they publish from `publisher` and `name`, so
57+
# anything this workflow states about the extension has to be read from
58+
# there too. A second copy here would decide which listing gets queried
59+
# while the manifest decided which listing gets written.
60+
PUBLISHER=$(node -p "require('./vscode-extension/package.json').publisher")
61+
NAME=$(node -p "require('./vscode-extension/package.json').name")
62+
EXT_ID="${PUBLISHER}.${NAME}"
63+
echo "publisher=$PUBLISHER" >> "$GITHUB_OUTPUT"
64+
echo "name=$NAME" >> "$GITHUB_OUTPUT"
65+
echo "extension-id=$EXT_ID" >> "$GITHUB_OUTPUT"
66+
5267
# A release is a version change, and nothing else. This workflow wakes
5368
# on any edit to the manifest, which also carries the icon, the
5469
# commands and the settings schema — so an unrelated edit would
@@ -68,14 +83,14 @@ jobs:
6883
6984
MKT=$(curl -s -X POST https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery \
7085
-H "Content-Type: application/json" -H "Accept: application/json;api-version=7.2-preview.1" \
71-
-d '{"filters":[{"criteria":[{"filterType":7,"value":"tumaet.apollon-vscode"}]}],"flags":914}' \
86+
-d "$(jq -nc --arg id "$EXT_ID" '{filters:[{criteria:[{filterType:7,value:$id}]}],flags:914}')" \
7287
| jq -r '.results[0].extensions[0].versions[]?.version' | grep -Fx "$VERSION" || true)
7388
if [ -n "$MKT" ]; then
7489
echo "publish=false" >> "$GITHUB_OUTPUT"
7590
else
7691
echo "publish=true" >> "$GITHUB_OUTPUT"
7792
fi
78-
TAG="apollon-vscode@${VERSION}"
93+
TAG="${NAME}@${VERSION}"
7994
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
8095
echo "release=false" >> "$GITHUB_OUTPUT"
8196
else
@@ -156,6 +171,8 @@ jobs:
156171
environment: vscode-marketplace
157172
permissions:
158173
contents: read
174+
outputs:
175+
ovsx: ${{ steps.ovsx.outputs.configured }}
159176
steps:
160177
# `.nvmrc` is the one source for the Node version, and this job has no
161178
# working tree to read it from. `checkout` cleans the directory, so it has
@@ -181,13 +198,39 @@ jobs:
181198
npm install --prefix "$RUNNER_TEMP/cli" --ignore-scripts @vscode/vsce@3.9.1 ovsx@0.10.12
182199
echo "$RUNNER_TEMP/cli/node_modules/.bin" >> "$GITHUB_PATH"
183200
201+
- name: Verify the Marketplace PAT can write this publisher
202+
env:
203+
VSCE_PAT: ${{ secrets.VSCE_PAT }}
204+
PUBLISHER: ${{ needs.check.outputs.publisher }}
205+
# `vsce publish` surfaces a missing publisher grant only after uploading,
206+
# so ask first. The manifest names the publisher; the PAT must be a member
207+
# of it with Marketplace *Manage* scope, or nothing else in this job works.
208+
run: vsce verify-pat "$PUBLISHER"
209+
184210
- name: Publish to VS Marketplace
185211
env:
186212
VSCE_PAT: ${{ secrets.VSCE_PAT }}
187213
VSIX_FILE: ${{ needs.build.outputs.vsix-name }}
188214
run: vsce publish --skip-duplicate --no-dependencies --packagePath "$VSIX_FILE"
189215

216+
# Open VSX is optional: the Marketplace is the release channel of record.
217+
# Without a token, say so and move on rather than failing a release that
218+
# already reached the Marketplace.
219+
- name: Check for an Open VSX token
220+
id: ovsx
221+
env:
222+
OVSX_PAT: ${{ secrets.OVSX_PAT }}
223+
run: |
224+
set -euo pipefail
225+
if [ -n "${OVSX_PAT:-}" ]; then
226+
echo "configured=true" >> "$GITHUB_OUTPUT"
227+
else
228+
echo "configured=false" >> "$GITHUB_OUTPUT"
229+
echo "::notice::OVSX_PAT is not set — skipping Open VSX. The VS Marketplace release is unaffected."
230+
fi
231+
190232
- name: Publish to Open VSX
233+
if: steps.ovsx.outputs.configured == 'true'
191234
env:
192235
OVSX_PAT: ${{ secrets.OVSX_PAT }}
193236
VSIX_FILE: ${{ needs.build.outputs.vsix-name }}
@@ -229,9 +272,13 @@ jobs:
229272
env:
230273
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
231274
VERSION: ${{ needs.check.outputs.version }}
275+
PUBLISHER: ${{ needs.check.outputs.publisher }}
276+
NAME: ${{ needs.check.outputs.name }}
277+
EXT_ID: ${{ needs.check.outputs.extension-id }}
278+
OVSX: ${{ needs.publish.outputs.ovsx }}
232279
run: |
233280
set -euo pipefail
234-
TAG="apollon-vscode@${VERSION}"
281+
TAG="${NAME}@${VERSION}"
235282
if ! git ls-remote --exit-code --tags origin "refs/tags/$TAG" >/dev/null 2>&1; then
236283
git config user.name "github-actions[bot]"
237284
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
@@ -252,16 +299,25 @@ jobs:
252299
# --generate-notes only when there is no changelog section for this
253300
# version (e.g. a release that carried no changeset).
254301
CHANGELOG=$(node scripts/extract-changelog.mjs "$VERSION" vscode-extension)
302+
303+
# Name the registries this release actually reached. Open VSX is
304+
# skipped when no token is configured, and a release body that claims
305+
# a publish that never happened is worse than one that omits it.
306+
REGISTRIES="the [VS Marketplace](https://marketplace.visualstudio.com/items?itemName=${EXT_ID})"
307+
if [ "${OVSX:-}" = "true" ]; then
308+
REGISTRIES="${REGISTRIES} and [Open VSX](https://open-vsx.org/extension/${PUBLISHER}/${NAME})"
309+
fi
310+
255311
{
256312
if [ -n "$CHANGELOG" ]; then printf '%s\n\n' "$CHANGELOG"; fi
257313
cat <<EOF
258314
Install:
259315
260316
\`\`\`sh
261-
code --install-extension tumaet.apollon-vscode
317+
code --install-extension ${EXT_ID}
262318
\`\`\`
263319
264-
Published to [VS Marketplace](https://marketplace.visualstudio.com/items?itemName=tumaet.apollon-vscode) and [Open VSX](https://open-vsx.org/extension/tumaet/apollon-vscode). VSIX attached for sideloading.
320+
Published to ${REGISTRIES}. VSIX attached for sideloading.
265321
EOF
266322
} > release-notes.md
267323

SECURITY.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ We aim to acknowledge reports within 5 working days and to coordinate a fix and
1010

1111
Only the latest minor of each major is supported with security fixes.
1212

13-
| Package | Supported |
14-
| --------------------------------------------------- | ---------------- |
15-
| `@tumaet/apollon` (npm) | `4.x` |
16-
| Standalone Docker images (server + webapp) | latest `vX.Y.Z` |
17-
| `tumaet.apollon-vscode` (VS Marketplace / Open VSX) | latest published |
13+
| Package | Supported |
14+
| ---------------------------------------------------- | ---------------- |
15+
| `@tumaet/apollon` (npm) | `4.x` |
16+
| Standalone Docker images (server + webapp) | latest `vX.Y.Z` |
17+
| `aet-tum.apollon-vscode` (VS Marketplace / Open VSX) | latest published |
1818

1919
Older majors are end-of-life and will not receive backports.
2020

docs/contributor/deployment/npm-publishing.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ description: How the three independently versioned Apollon artifacts ship — np
88

99
Three independently versioned artifacts, each with its own release workflow:
1010

11-
| Artifact | Version source | Tag | Workflow |
12-
| --------------------------------------------------- | ----------------------------------------- | ----------------------- | ------------------------------ |
13-
| `@tumaet/apollon` (npm) | `library/package.json` | `@tumaet/apollon@X.Y.Z` | `release-library.yml` |
14-
| Standalone Docker images | `standalone/{webapp,server}/package.json` | `vX.Y.Z` | `release-standalone.yml` |
15-
| `tumaet.apollon-vscode` (VS Marketplace + Open VSX) | `vscode-extension/package.json` | `apollon-vscode@X.Y.Z` | `release-vscode-extension.yml` |
11+
| Artifact | Version source | Tag | Workflow |
12+
| ---------------------------------------------------- | ----------------------------------------- | ----------------------- | ------------------------------ |
13+
| `@tumaet/apollon` (npm) | `library/package.json` | `@tumaet/apollon@X.Y.Z` | `release-library.yml` |
14+
| Standalone Docker images | `standalone/{webapp,server}/package.json` | `vX.Y.Z` | `release-standalone.yml` |
15+
| `aet-tum.apollon-vscode` (VS Marketplace + Open VSX) | `vscode-extension/package.json` | `apollon-vscode@X.Y.Z` | `release-vscode-extension.yml` |
1616

1717
Standalone starts at `4.2.18` (the library version at the time of the release-pipeline switchover). Future `vX.Y.Z` tags advance from there and do not collide with legacy tags.
1818

@@ -36,7 +36,7 @@ The GitHub Release body for each track is built from that `CHANGELOG.md` section
3636
2. On merge:
3737
- `release-library.yml` fires when `library/package.json` changes: builds with pnpm, packs the tarball with `pnpm pack`, publishes with `npm publish` for OIDC trusted publishing + provenance (pnpm does not yet support OIDC trusted publishing natively — tracked in [pnpm#9812](https://github.com/pnpm/pnpm/issues/9812)). Tags `@tumaet/apollon@X.Y.Z` → GitHub Release. Skipped if the version is already on npm.
3838
- `release-standalone.yml` fires after the push-to-main Docker build succeeds: retag `sha-<commit>``X.Y.Z` → cosign-sign → tag `vX.Y.Z` → GitHub Release. Staging is already running the same digest under the `sha-<commit>` tag from the push-to-main deploy, so no second deploy is needed. Skipped if a release for that version already exists.
39-
- `release-vscode-extension.yml` fires when `vscode-extension/package.json` changes: builds the library + extension, packages the VSIX, attests it via sigstore (`actions/attest-build-provenance`), then publishes to both VS Marketplace (`vsce`) and Open VSX (`ovsx`) gated on the `vscode-marketplace` environment. Tags `apollon-vscode@X.Y.Z` → GitHub Release with the VSIX attached.
39+
- `release-vscode-extension.yml` fires when the `version` in `vscode-extension/package.json` changes: builds the library + extension, packages the VSIX, attests it via sigstore (`actions/attest-build-provenance`), then publishes to the VS Marketplace (`vsce`) and, when `OVSX_PAT` is set, to Open VSX (`ovsx`) — both gated on the `vscode-marketplace` environment. Tags `apollon-vscode@X.Y.Z` → GitHub Release with the VSIX attached. Any other edit to the manifest, including the `publisher` and `name` that decide the Marketplace identity, is picked up by the next release rather than triggering one; publish it with a `workflow_dispatch`.
4040
3. Promote standalone to production: Actions → **Deploy to Production**`image-tag: X.Y.Z`.
4141

4242
## Verify a Docker image signature
@@ -57,13 +57,15 @@ cosign verify \
5757

5858
### VS Marketplace + Open VSX (vscode-extension)
5959

60-
- **Azure DevOps PAT**: create at `https://dev.azure.com/<your-org>/_usersSettings/tokens` with scope `Marketplace → Manage`, organization "All accessible organizations". Max lifetime is 1 year — calendar a rotation reminder.
61-
- **Open VSX PAT**: create at `https://open-vsx.org/user-settings/tokens`. The namespace `tumaet` must exist on Open VSX first — if it doesn't, run `ovsx create-namespace tumaet -p <PAT>` once locally (or have any namespace member do it). Verify at `https://open-vsx.org/namespace/tumaet`.
60+
The extension publishes as `aet-tum.apollon-vscode`, from the `publisher` and `name` fields of `vscode-extension/package.json`. `aet-tum` is the organization's publisher — the one that also owns `aet-tum.iris-thaumantias`.
61+
62+
- **Azure DevOps PAT** (required): create at `https://dev.azure.com/<your-org>/_usersSettings/tokens` with scope `Marketplace → Manage`, organization "All accessible organizations". Max lifetime is 1 year — calendar a rotation reminder. The PAT's account must be a member of the `aet-tum` publisher: a token that is valid but not a member fails with `Access Denied … needs the following permission(s) on the resource /aet-tum/apollon-vscode`. Check with `vsce verify-pat aet-tum`; the release workflow runs the same command before it uploads anything.
63+
- **Open VSX PAT** (optional): create at `https://open-vsx.org/user-settings/tokens`. When `OVSX_PAT` is unset the release skips Open VSX and publishes to the Marketplace alone; the workflow logs a notice and stays green. The namespace `aet-tum` must exist on Open VSX — verify at `https://open-vsx.org/namespace/aet-tum`, and if it is missing run `ovsx create-namespace aet-tum -p <PAT>` once locally.
6264
- **GitHub Environment `vscode-marketplace`**:
6365
- Settings → Environments → New environment → name `vscode-marketplace`.
6466
- Deployment branches and tags → "Selected branches and tags" → add `main`.
6567
- Required reviewers → add the release maintainer; turn on "Prevent self-review" if a second maintainer is available.
6668
- Environment secrets:
6769
- `VSCE_PAT` = Azure DevOps PAT (above).
68-
- `OVSX_PAT` = Open VSX PAT (above).
70+
- `OVSX_PAT` = Open VSX PAT (above), if Open VSX is wanted.
6971
- Delete any pre-existing repo-level `VSCE_PAT` / `OVSX_PAT` after the environment-scoped ones are in place — repo secrets bypass the environment's deployment-branch and reviewer gates.

docs/contributor/development/project-structure.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,16 @@ Apollon/
4545

4646
## Workspaces
4747

48-
| Workspace | Name | Published as |
49-
| --------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------ |
50-
| `library/` | `@tumaet/apollon` | [npm](https://www.npmjs.com/package/@tumaet/apollon) |
51-
| `packages/ui/` | `@tumaet/ui` | internal design system (consumed by the webapp; not published) |
52-
| `standalone/webapp/` | `@tumaet/webapp` | `ghcr.io/ls1intum/apollon/webapp` |
53-
| `standalone/server/` | `@tumaet/server` | `ghcr.io/ls1intum/apollon/server` |
54-
| `vscode-extension/` | `apollon-vscode` | [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=tumaet.apollon-vscode) |
55-
| `vscode-extension/webview/` | `@tumaet/vscode-webview` | bundled into the extension VSIX |
56-
| `docs/` | `@tumaet/docs` | published as the Docusaurus site at <https://ls1intum.github.io/Apollon/> |
48+
| Workspace | Name | Published as |
49+
| --------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------- |
50+
| `library/` | `@tumaet/apollon` | [npm](https://www.npmjs.com/package/@tumaet/apollon) |
51+
| `packages/ui/` | `@tumaet/ui` | internal design system (consumed by the webapp; not published) |
52+
| `standalone/webapp/` | `@tumaet/webapp` | `ghcr.io/ls1intum/apollon/webapp` |
53+
| `standalone/server/` | `@tumaet/server` | `ghcr.io/ls1intum/apollon/server` |
54+
| `vscode-extension/` | `apollon-vscode` | [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=aet-tum.apollon-vscode) |
55+
| `vscode-extension/webview/` | `@tumaet/vscode-webview` | bundled into the extension VSIX |
56+
| `docs/` | `@tumaet/docs` | published as the Docusaurus site at <https://ls1intum.github.io/Apollon/> |
5757

58-
The scope carries the organization and the name carries the role, so `@tumaet/apollon` is the product and every other workspace is named for the job it does. `apollon-vscode` is the sole exception: the VS Code Marketplace requires an extension name to match `[a-z0-9][a-z0-9-]*`, so `vsce` rejects a scope outright. Its Marketplace identity, `tumaet.apollon-vscode`, is the same name spelled the way the Marketplace spells scopes — and it is fixed for good, because the identity is what installed clients follow for updates.
58+
The scope carries the organization and the name carries the role, so `@tumaet/apollon` is the product and every other workspace is named for the job it does. `apollon-vscode` is the sole exception: the VS Code Marketplace requires an extension name to match `[a-z0-9][a-z0-9-]*`, so `vsce` rejects a scope outright.
59+
60+
Its Marketplace identity is `publisher.name``aet-tum.apollon-vscode`, where `aet-tum` is the organization's publisher, alongside `aet-tum.iris-thaumantias`. `publisher` and `name` in `vscode-extension/package.json` are the only source for that identity: the release workflow reads both to decide which listing to query, which tag to cut, and what to print in the release notes. Changing either points the release at a different listing, and installed clients follow the identity, not the repository — a new identity reaches nobody who already has the extension.

docs/docusaurus.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ const config: Config = {
218218
},
219219
{
220220
label: "VS Code Extension",
221-
href: "https://marketplace.visualstudio.com/items?itemName=tumaet.apollon-vscode",
221+
href: "https://marketplace.visualstudio.com/items?itemName=aet-tum.apollon-vscode",
222222
},
223223
{
224224
label: "Release Notes",

docs/user/getting-started/setup.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Open <https://apollon.aet.cit.tum.de> in a browser. No install, no account. Diag
1515

1616
## VS Code extension
1717

18-
Install **Apollon** from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=tumaet.apollon-vscode) (or [Open VSX](https://open-vsx.org/extension/tumaet/apollon-vscode)). Diagrams live next to your code as `.apollon` files.
18+
Install **Apollon** from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=aet-tum.apollon-vscode) (or [Open VSX](https://open-vsx.org/extension/aet-tum/apollon-vscode)). Diagrams live next to your code as `.apollon` files.
1919

2020
## Self-host
2121

library/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ The server-side wire protocol is exposed through the `@tumaet/apollon/internals`
266266

267267
- Source and issues: <https://github.com/ls1intum/Apollon>
268268
- Live editor: <https://apollon.aet.cit.tum.de>
269-
- The standalone web editor, collaboration server, and [VS Code extension](https://marketplace.visualstudio.com/items?itemName=tumaet.apollon-vscode) live in the same monorepo.
269+
- The standalone web editor, collaboration server, and [VS Code extension](https://marketplace.visualstudio.com/items?itemName=aet-tum.apollon-vscode) live in the same monorepo.
270270

271271
## License
272272

0 commit comments

Comments
 (0)