Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
41c3a91
feat: add VS Code extension CI/CD infrastructure
madhur310 May 22, 2026
55e1261
test: add workflows to test vscode-extension-ci integration
madhur310 May 26, 2026
a752f30
chore: update .gitignore to exclude build artifacts
madhur310 May 26, 2026
7ee71a4
chore: remove dist/ files from git tracking
madhur310 May 26, 2026
e3b396f
fix: only run test workflows on manual dispatch
madhur310 May 26, 2026
e75c767
fix: move VS Code workflows to top level and enable push triggers
madhur310 May 26, 2026
89a6826
fix: replace complex test workflows with simple package test
madhur310 May 26, 2026
3b6317e
fix: make package tsconfig self-contained
madhur310 May 26, 2026
18c18c1
test: add integration test workflow for VS Code workflows
madhur310 May 26, 2026
6d32dd6
fix: simplify integration test workflow
madhur310 May 26, 2026
f38c9fc
fix: add push trigger to integration test workflow
madhur310 May 26, 2026
9d4a1de
fix: correct path indentation in checkout action
madhur310 May 26, 2026
ab1b9df
fix: replace require() with ES module imports
madhur310 May 26, 2026
d82fcac
fix: use correct package script name
madhur310 May 26, 2026
e6782a9
Fix nested workflow calls to use absolute paths
madhur310 May 26, 2026
db4cc93
Fix composite action references to use absolute paths
madhur310 May 26, 2026
294a519
Add prepare script to build package on install
madhur310 May 26, 2026
6021653
Add prepare script to root to build workspaces on install
madhur310 May 26, 2026
4316ec0
Use full path to CLI instead of npx
madhur310 May 26, 2026
09fc8cf
fix: try adding dist to access crop repo
madhur310 Jun 18, 2026
fe648bc
fix: remove prepare script
madhur310 Jun 18, 2026
7926460
fix: remove prepare script
madhur310 Jun 18, 2026
6ac5088
chore: add .npmrc to skip devDependencies for git dep consumers
madhur310 Jun 18, 2026
cce39d5
fix: flattened structure
madhur310 Jun 18, 2026
2117fae
fix: remove devD
madhur310 Jun 18, 2026
9c0f25d
feat: add vscode-nightly-release reusable workflow
madhur310 Jun 22, 2026
3326a32
fix: multi-line json
madhur310 Jun 23, 2026
cf1f10f
feat: add configurable package-command input
madhur310 Jun 23, 2026
1eac392
fix: compile extensions before packaging
madhur310 Jun 23, 2026
ed0b0f2
debug: add step to list compiled files
madhur310 Jun 23, 2026
a6f2a36
fix: add vscode:bundle step to create dist files
madhur310 Jun 23, 2026
21dd4e1
fix: extract bundling
madhur310 Jun 23, 2026
1da8726
feat: make bundle command optional and check for script existence
madhur310 Jun 23, 2026
9c0ab55
fix: array fix
madhur310 Jun 23, 2026
bedca81
fix: add / fix
madhur310 Jun 23, 2026
365f18d
fix: add changes
madhur310 Jun 23, 2026
b7950b7
feat: add vscode-release-explicit workflow for JSON array inputs
madhur310 Jun 24, 2026
687582d
fix: delete code
madhur310 Jun 24, 2026
a50486a
fix delete code
madhur310 Jun 25, 2026
bfee832
fix: delete unused code
madhur310 Jun 25, 2026
8548701
Merge branch 'main' into feat/add-vscode-extension-ci
madhur310 Jun 26, 2026
1c725e4
chore: remove unused workflows and actions
madhur310 Jun 26, 2026
1cfd2c0
refactor: replace redundant vscode/npm-install-with-retries with exis…
madhur310 Jun 26, 2026
bc7d223
docs: restore original README and append VS Code workflow docs
madhur310 Jun 26, 2026
f88f63d
fix: clean up gitignore
madhur310 Jun 26, 2026
899b6dc
fix: clean up gitignore
madhur310 Jun 26, 2026
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/actions/vscode/publish-vsix/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
name: "Publish VSIX"
description: "Publishes VSIX files to a marketplace with dry-run support"

inputs:
vsix-path:
description: "Path to the VSIX file to publish"
required: true
publish-tool:
description: "Publishing tool to use"
required: true
pre-release:
description: "Publish as pre-release version"
required: false
default: "false"
dry-run:
description: "Run in dry-run mode"
required: false
default: "false"

runs:
using: composite
steps:
- name: Validate inputs
shell: bash
run: |
# Validate VSIX path exists
if [ ! -f "${{ inputs.vsix-path }}" ]; then
echo "❌ Error: VSIX file not found at ${{ inputs.vsix-path }}"
exit 1
fi

# Validate VSIX file extension
if [[ ! "${{ inputs.vsix-path }}" =~ \.vsix$ ]]; then
echo "❌ Error: File must have .vsix extension"
exit 1
fi

# Validate publish tool
if [[ ! "${{ inputs.publish-tool }}" =~ ^(ovsx|vsce)$ ]]; then
echo "❌ Error: Invalid publish tool: ${{ inputs.publish-tool }}"
exit 1
fi

echo "✅ Input validation passed"

- name: Audit publish attempt
shell: bash
run: |
# Create audit log entry
AUDIT_LOG="/tmp/publish_audit.log"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
ACTOR="${{ github.actor }}"
REPO="${{ github.repository }}"
RUN_ID="${{ github.run_id }}"
WORKFLOW="${{ github.workflow }}"

# Get file info for audit
FILE_SIZE=$(stat -c%s "${{ inputs.vsix-path }}" 2>/dev/null || stat -f%z "${{ inputs.vsix-path }}" 2>/dev/null || echo "unknown")
FILE_HASH=$(sha256sum "${{ inputs.vsix-path }}" 2>/dev/null | cut -d' ' -f1 || echo "unknown")

# Log audit information
echo "[$TIMESTAMP] PUBLISH_ATTEMPT: actor=$ACTOR, repo=$REPO, run_id=$RUN_ID, workflow=$WORKFLOW, tool=${{ inputs.publish-tool }}, file=${{ inputs.vsix-path }}, size=$FILE_SIZE, hash=$FILE_HASH, pre_release=${{ inputs.pre-release }}, dry_run=${{ inputs.dry-run }}" >> "$AUDIT_LOG"

# Also log to GitHub Actions output for visibility
echo "🔍 AUDIT: Publish attempt logged - $TIMESTAMP"
echo " Actor: $ACTOR"
echo " Repository: $REPO"
echo " Run ID: $RUN_ID"
echo " Workflow: $WORKFLOW"
echo " Tool: ${{ inputs.publish-tool }}"
echo " File: ${{ inputs.vsix-path }}"
echo " Size: $FILE_SIZE bytes"
echo " Hash: $FILE_HASH"
echo " Pre-release: ${{ inputs.pre-release }}"
echo " Dry-run: ${{ inputs.dry-run }}"

- name: Publish VSIX
shell: bash
run: |
echo "Publishing ${{ inputs.vsix-path }}"

# Calculate marketplace name based on publish tool
if [ "${{ inputs.publish-tool }}" = "ovsx" ]; then
MARKETPLACE_NAME="Open VSX Registry"
TOKEN_ENV="OVSX_PAT"
else
MARKETPLACE_NAME="Visual Studio Marketplace"
TOKEN_ENV="VSCE_PERSONAL_ACCESS_TOKEN"
fi

PRE_RELEASE_FLAG=""
if [ "${{ inputs.pre-release }}" = "true" ]; then
PRE_RELEASE_FLAG="--pre-release"
echo "Would publish as pre-release version"
fi

# Mask token in logs for security
TOKEN_MASK="***"

if [ "${{ inputs.dry-run }}" = "true" ]; then
echo "🔍 DRY RUN MODE - Would publish to $MARKETPLACE_NAME:"
echo " VSIX: ${{ inputs.vsix-path }}"
echo " Pre-release: ${{ inputs.pre-release }}"

if [ "${{ inputs.publish-tool }}" = "ovsx" ]; then
echo " Command: npx ovsx publish \"${{ inputs.vsix-path }}\" -p $TOKEN_MASK $PRE_RELEASE_FLAG"
else
echo " Command: npx @vscode/vsce publish --packagePath \"${{ inputs.vsix-path }}\" --skip-duplicate $PRE_RELEASE_FLAG"
fi
echo "✅ Dry run completed - no actual publish performed"
else
echo "Publishing VSIX: ${{ inputs.vsix-path }}"

# Verify token is available
if [ -z "${!TOKEN_ENV}" ]; then
echo "❌ Error: $TOKEN_ENV environment variable is not set"
exit 1
fi

if [ "${{ inputs.publish-tool }}" = "vsce" ]; then
export VSCE_PAT="${!TOKEN_ENV}" # ensure the expected env var is set
npx @vscode/vsce publish --packagePath "${{ inputs.vsix-path }}" --skip-duplicate $PRE_RELEASE_FLAG
else
npx ovsx publish "${{ inputs.vsix-path }}" -p "${!TOKEN_ENV}" --skip-duplicate $PRE_RELEASE_FLAG
fi

echo "✅ Successfully published to $MARKETPLACE_NAME"
fi

- name: Audit publish result
shell: bash
if: inputs.dry-run != 'true'
run: |
# Log the result of the publish attempt
AUDIT_LOG="/tmp/publish_audit.log"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
ACTOR="${{ github.actor }}"
REPO="${{ github.repository }}"
RUN_ID="${{ github.run_id }}"

if [ $? -eq 0 ]; then
echo "[$TIMESTAMP] PUBLISH_SUCCESS: actor=$ACTOR, repo=$REPO, run_id=$RUN_ID, tool=${{ inputs.publish-tool }}, file=${{ inputs.vsix-path }}" >> "$AUDIT_LOG"
echo "✅ AUDIT: Publish successful - $TIMESTAMP"
else
echo "[$TIMESTAMP] PUBLISH_FAILURE: actor=$ACTOR, repo=$REPO, run_id=$RUN_ID, tool=${{ inputs.publish-tool }}, file=${{ inputs.vsix-path }}" >> "$AUDIT_LOG"
echo "❌ AUDIT: Publish failed - $TIMESTAMP"
fi
215 changes: 215 additions & 0 deletions .github/workflows/vscode-ci-template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
name: CI

# Reusable CI workflow template for VS Code extension repositories
#
# Usage from consuming repository:
# jobs:
# ci:
# uses: salesforcecli/github-workflows/.github/workflows/vscode/ci-template.yml@main
# with:
# lint-command: 'npm run lint'
# compile-command: 'npm run compile'
# test-command: 'npm run test'
# test-coverage-command: 'npm run test:coverage'
#
# Features:
# - Tests across multiple OS (Ubuntu, Windows)
# - Tests across Node.js versions (lts/-1, lts/*, current)
# - Coverage collection and reporting
# - Parallel test execution
# - Artifact upload for coverage reports

on:
workflow_call:
inputs:
lint-command:
description: 'Command to run linting'
required: false
default: 'npm run lint'
type: string
compile-command:
description: 'Command to compile'
required: false
default: 'npm run compile'
type: string
test-command:
description: 'Command to run tests (without coverage)'
required: false
default: 'npm run test'
type: string
test-coverage-command:
description: 'Command to run tests with coverage'
required: false
default: 'npm run test:coverage'
type: string
coverage-report-command:
description: 'Command to merge coverage reports'
required: false
default: 'npm run test:coverage:report'
type: string
workflow_dispatch:
inputs:
lint-command:
description: 'Command to run linting'
required: false
default: 'npm run lint'
type: string

# Add explicit permissions for security
permissions:
contents: read
pull-requests: read
actions: read

jobs:
test:
name: Test
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node-version: ['lts/-1', 'lts/*', 'current']
fail-fast: false

runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
persist-credentials: false
submodules: false

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Install dependencies
uses: salesforcecli/github-workflows/.github/actions/npmInstallWithRetries@main

- name: Run linting
run: ${{ inputs.lint-command }}

- name: Compile project
run: ${{ inputs.compile-command }}

- name: Run tests with coverage (lts/current)
if: ${{ matrix.node-version != 'lts/-1' }}
run: ${{ inputs.test-coverage-command }}

- name: Run tests (lts/-1, no coverage)
if: ${{ matrix.node-version == 'lts/-1' }}
env:
# Old-LTS defaults to ~4 GB old-space, which is too low for heavy stdlib suites.
# Keep this scoped to lts/-1 and non-coverage runs only.
NODE_OPTIONS: --max-old-space-size=6144
run: ${{ inputs.test-command }}

- name: Merge coverage reports
if: ${{ matrix.node-version != 'lts/-1' }}
run: ${{ inputs.coverage-report-command }}

- name: Determine Node Label
id: node-label
shell: bash
env:
NODE_VERSION: ${{ matrix.node-version }}
run: |
if [ "$NODE_VERSION" = "lts/*" ]; then
echo "value=lts" >> $GITHUB_OUTPUT
elif [ "$NODE_VERSION" = "lts/-1" ]; then
echo "value=lts-1" >> $GITHUB_OUTPUT
elif [ "$NODE_VERSION" = "current" ]; then
echo "value=current" >> $GITHUB_OUTPUT
else
echo "value=$NODE_VERSION" >> $GITHUB_OUTPUT
fi

- name: Upload coverage report
if: ${{ matrix.node-version != 'lts/-1' }}
uses: actions/upload-artifact@v7
with:
name: coverage-report-${{ matrix.os }}-${{ steps.node-label.outputs.value }}
path: ./coverage

test-quality:
name: Test Quality
needs: test
strategy:
matrix:
os: [ubuntu-latest]
node-version: ['lts/*']
fail-fast: false

runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
persist-credentials: false
submodules: false

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Install dependencies
uses: salesforcecli/github-workflows/.github/actions/npmInstallWithRetries@main

- name: Run quality tests
run: npm run test:quality

package:
name: Package
needs: test
if: ${{ needs.test.result == 'success' }}
uses: salesforcecli/github-workflows/.github/workflows/vscode-package.yml@feat/add-vscode-extension-ci
with:
branch: ${{ github.head_ref || github.ref_name }}
artifact-name: vsix-packages
dry-run: false

ci-complete:
name: CI Complete
runs-on: ubuntu-latest
needs: [test, package]
if: always()
steps:
- name: Check all jobs result
env:
TEST_RESULT: ${{ needs.test.result }}
PACKAGE_RESULT: ${{ needs.package.result }}
run: |
if [[ "$TEST_RESULT" != "success" ]]; then
echo "Test job(s) failed"
exit 1
fi
if [[ "$PACKAGE_RESULT" != "success" ]]; then
echo "Package job failed"
exit 1
fi
echo "All jobs succeeded"

slack-notify:
name: CI Failed Notification
needs: [test, package]
runs-on: ubuntu-latest
if: always() && github.event_name == 'push' && (needs.test.result == 'failure' || needs.package.result == 'failure')
steps:
- name: Notify Slack
uses: slackapi/slack-github-action@v3.0.3
with:
payload: |
{
"text": "❌ CI Pipeline Failed",
"event": "CI workflow failed, run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"repo": "${{ github.repository }}",
"test_result": "${{ needs.test.result }}",
"package_result": "${{ needs.package.result }}",
"branch": "${{ github.ref_name }}",
"commit": "${{ github.sha }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.IDEE_MAIN_SLACK_WEBHOOK }}
Loading