Skip to content
Closed
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
32 changes: 25 additions & 7 deletions .github/workflows/openvsx-publish-release-vsix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,28 @@ on:
required: false
default: false
type: boolean
secrets:
IDEE_OVSX_PAT:
description: Open VSX publishing token
required: true
vsix-name-pattern:
description: Glob of downloaded VSIX file names to publish
required: false
default: '*.vsix'
type: string
exclude-web-vsix:
description: Exclude *-web-* VSIXs from publishing
required: false
default: 'false'
type: string

permissions:
contents: read

jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
# ovsx exchanges this job's OIDC ID token for a short-lived Open VSX publishing token
# (--trusted-publishing below) -- without this, there is no token to exchange.
id-token: write
steps:
- name: Download release VSIXs
id: release
Expand All @@ -33,8 +44,9 @@ jobs:
- name: Publish VSIXs
env:
DRY_RUN: ${{ inputs.dry-run }}
IDEE_OVSX_PAT: ${{ secrets.IDEE_OVSX_PAT }}
PRE_RELEASE: ${{ steps.release.outputs.pre-release }}
VSIX_PATTERN: ${{ inputs.vsix-name-pattern }}
EXCLUDE_WEB: ${{ inputs.exclude-web-vsix }}
run: |
# Open VSX can hang the same way as vsce; retry per VSIX.
# --skip-duplicate makes a retry a no-op if the first attempt committed.
Expand All @@ -54,7 +66,7 @@ jobs:
}

while IFS= read -r -d '' vsix; do
args=("$vsix" -p "$IDEE_OVSX_PAT" --skip-duplicate)
args=("$vsix" --trusted-publishing --skip-duplicate)
pre_release_suffix=''
if [ "$PRE_RELEASE" = true ]; then
args+=(--pre-release)
Expand All @@ -70,4 +82,10 @@ jobs:
echo "::error::Failed to publish $vsix after 3 attempts"
exit 1
fi
done < <(find extensions -type f -name '*.vsix' -print0)
done < <(
if [ "$EXCLUDE_WEB" = "true" ]; then
find extensions -type f -name "$VSIX_PATTERN" ! -iname '*-web-*' -print0
else
find extensions -type f -name "$VSIX_PATTERN" -print0
fi
)
81 changes: 39 additions & 42 deletions .github/workflows/vscode-promote-prerelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ name: Promote Nightly to Pre-release
# Requirements - calling repository must have:
# - Nightly tags matching *-nightly.* (e.g., v1.2.3-nightly.20260629)
# - GitHub releases for each nightly tag with VSIX file(s) attached
# - Secrets: IDEE_GH_TOKEN, VSCE_PERSONAL_ACCESS_TOKEN, IDEE_OVSX_PAT
# - Secrets: IDEE_GH_TOKEN, VSCE_PERSONAL_ACCESS_TOKEN
# - Open VSX publishes via OIDC trusted publishing (--trusted-publishing) -- no secret needed,
# but the registry's trusted-publisher config must list this workflow file
#
# Workflow: downloads VSIX → publishes to both marketplaces → creates tracking tag

Expand Down Expand Up @@ -116,18 +118,13 @@ permissions:
contents: write
packages: write
actions: read
# ovsx exchanges this for a short-lived Open VSX publishing token (--trusted-publishing in the
# publish job below); vsce/Marketplace still uses VSCE_PERSONAL_ACCESS_TOKEN.
id-token: write

jobs:
publish:
publish-vsce:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- registry: vsce
publish-tool: vsce
- registry: ovsx
publish-tool: ovsx
steps:
- name: Checkout
uses: actions/checkout@v6
Expand All @@ -151,15 +148,13 @@ jobs:
--dir ./vsix-artifacts \
--repo "${{ github.repository }}"

- name: Publish to ${{ matrix.registry }}
- name: Publish to Visual Studio Marketplace
env:
NIGHTLY_TAG: ${{ inputs.release-tag }}
VSIX_PATTERN: ${{ inputs.vsix-name-pattern || '*.vsix' }}
EXCLUDE_WEB: ${{ inputs.exclude-web-vsix || 'false' }}
PUBLISH_TOOL: ${{ matrix.publish-tool }}
DRY_RUN: ${{ inputs.dry-run || 'false' }}
VSCE_PERSONAL_ACCESS_TOKEN: ${{ secrets.VSCE_PERSONAL_ACCESS_TOKEN }}
OVSX_PAT: ${{ secrets.IDEE_OVSX_PAT }}
run: |
set -uo pipefail

Expand All @@ -177,20 +172,13 @@ jobs:
exit 1
fi

if [ "$PUBLISH_TOOL" = "ovsx" ]; then
MARKETPLACE_NAME="Open VSX Registry"
TOKEN="$OVSX_PAT"
else
MARKETPLACE_NAME="Visual Studio Marketplace"
TOKEN="$VSCE_PERSONAL_ACCESS_TOKEN"
fi

TOKEN="$VSCE_PERSONAL_ACCESS_TOKEN"
if [ "$DRY_RUN" != "true" ] && [ -z "$TOKEN" ]; then
echo "::error::Token for $PUBLISH_TOOL is not set"
echo "::error::Token for vsce is not set"
exit 1
fi

echo "Publishing ${#VSIX_FILES[@]} VSIX(s) as pre-release to $MARKETPLACE_NAME:"
echo "Publishing ${#VSIX_FILES[@]} VSIX(s) as pre-release to Visual Studio Marketplace:"
printf ' %s\n' "${VSIX_FILES[@]}"

RUN_ID="${{ github.run_id }}"
Expand All @@ -199,7 +187,7 @@ jobs:
FAILED=0

# Marketplace gallery requests can sit until typed-rest-client's 180s
# socket timeout. vsce/ovsx have no timeout flag; retry per VSIX.
# socket timeout. vsce has no timeout flag; retry per VSIX.
# --skip-duplicate makes a retry a no-op if the first attempt committed.
publish_with_retry() {
local attempt
Expand All @@ -218,44 +206,53 @@ jobs:

for VSIX in "${VSIX_FILES[@]}"; do
NAME=$(basename "$VSIX")
echo "::group::$NAME → $MARKETPLACE_NAME"
echo "::group::$NAME → Visual Studio Marketplace"

# Audit trail (mirrors the publish-vsix action's per-file record)
HASH=$(sha256sum "$VSIX" 2>/dev/null | cut -d' ' -f1 || echo "unknown")
echo "[AUDIT] actor=$ACTOR repo=$REPO run_id=$RUN_ID tool=$PUBLISH_TOOL file=$NAME hash=$HASH pre_release=true dry_run=$DRY_RUN"
echo "[AUDIT] actor=$ACTOR repo=$REPO run_id=$RUN_ID tool=vsce file=$NAME hash=$HASH pre_release=true dry_run=$DRY_RUN"

if [ "$DRY_RUN" = "true" ]; then
echo "🔍 DRY RUN - would publish $NAME (pre-release)"
echo "::endgroup::"
continue
fi

if [ "$PUBLISH_TOOL" = "vsce" ]; then
if VSCE_PAT="$TOKEN" publish_with_retry npx @vscode/vsce publish --packagePath "$VSIX" --skip-duplicate --pre-release; then
echo "✅ Published $NAME to $MARKETPLACE_NAME"
else
echo "::error::Failed to publish $NAME to $MARKETPLACE_NAME"
FAILED=1
fi
if VSCE_PAT="$TOKEN" publish_with_retry npx @vscode/vsce publish --packagePath "$VSIX" --skip-duplicate --pre-release; then
echo "✅ Published $NAME to Visual Studio Marketplace"
else
if publish_with_retry npx ovsx publish "$VSIX" -p "$TOKEN" --skip-duplicate --pre-release; then
echo "✅ Published $NAME to $MARKETPLACE_NAME"
else
echo "::error::Failed to publish $NAME to $MARKETPLACE_NAME"
FAILED=1
fi
echo "::error::Failed to publish $NAME to Visual Studio Marketplace"
FAILED=1
fi
echo "::endgroup::"
done

if [ "$FAILED" -ne 0 ]; then
echo "::error::One or more VSIX publishes failed for $PUBLISH_TOOL"
echo "::error::One or more VSIX publishes failed for vsce"
exit 1
fi
echo "✅ All ${#VSIX_FILES[@]} VSIX(s) processed for $MARKETPLACE_NAME"
echo "✅ All ${#VSIX_FILES[@]} VSIX(s) processed for Visual Studio Marketplace"

# ovsx publishing delegates to the shared workflow stable releases already use (rather than
# running its own `ovsx publish`), so every Open VSX publish for this extension -- prerelease
# and stable alike -- requests its OIDC token from the same job_workflow_ref. Open VSX's
# trusted-publisher config is one identity per extension, keyed on that exact file, so two
# different files here would mean only one of the two publish paths could ever be trusted.
publish-ovsx:
permissions:
contents: read
id-token: write
uses: salesforcecli/github-workflows/.github/workflows/openvsx-publish-release-vsix.yml@main
with:
release-tag: ${{ inputs.release-tag }}
vsix-name-pattern: ${{ inputs.vsix-name-pattern || '*.vsix' }}
exclude-web-vsix: ${{ inputs.exclude-web-vsix || 'false' }}
# This workflow's own dry-run input is a string ('true'/'false'); the callee's is boolean.
dry-run: ${{ (inputs.dry-run || 'false') == 'true' }}
secrets: inherit

tag-promoted:
needs: publish
needs: [publish-vsce, publish-ovsx]
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand Down
Loading