microsoft/vscode

13 workflows · maturity 50% · 9 patterns · GitHub ↗

Security 15.38/100

Practices

○ Matrix✓ Permissions○ Security scan○ AI review✓ Cache✓ Concurrency✓ Reusable workflows

Detected patterns

Security dimensions

permissions
15.4
security scan
0
supply chain
0
secret handling
0
harden runner
0

Workflows (13)

api-proposal-version-check perms .github/workflows/api-proposal-version-check.yml
Triggers
pull_request, issue_comment
Runs on
ubuntu-latest
Jobs
check-version-changes
Commands
  • echo "Override comment found by ${{ steps.check_override.outputs.override_user }}" echo "API proposal version change has been acknowledged."
  • set -e # Use merge-base to get accurate diff of what the PR actually changes MERGE_BASE=$(git merge-base "$BASE_SHA" "$HEAD_SHA") echo "Merge base: $MERGE_BASE" # Get the list of changed proposed API files (diff against merge-base) CHANGED_FILES=$(git diff --name-only "$MERGE_BASE" "$HEAD_SHA" -- 'src/vscode-dts/vscode.proposed.*.d.ts' || true) if [ -z "$CHANGED_FILES" ]; then echo "No proposed API files changed" echo "version_changed=false" >> $GITHUB_OUTPUT exit 0 fi echo "Changed proposed API files:" echo "$CHANGED_FILES" VERSION_CHANGED="false" CHANGED_LIST="" for FILE in $CHANGED_FILES; do # Check if file exists in head if ! git cat-file -e "$HEAD_SHA:$FILE" 2>/dev/null; then echo "File $FILE was deleted, skipping version check" continue fi # Get version from head (current PR) HEAD_VERSION=$(git show "$HEAD_SHA:$FILE" | grep -E '^// version: [0-9]+' | sed 's/.*version: //' || echo "") # Get version from merge-base (what the PR is based on) BASE_VERSION=$(git show "$MERGE_BASE:$FILE" 2>/dev/null | grep -E '^// version: [0-9]+' | sed 's/.*version: //' || echo "") echo "File: $FILE" echo " Base version: ${BASE_VERSION:-'(none)'}" echo " Head version: ${HEAD_VERSION:-'(none)'}" # Check if version was added or changed if [ -n "$HEAD_VERSION" ] && [ "$HEAD_VERSION" != "$BASE_VERSION" ]; then echo " -> Version changed!" VERSION_CHANGED="true" FILENAME=$(basename "$FILE") if [ -n "$CHANGED_LIST" ]; then CHANGED_LIST="$CHANGED_LIST, $FILENAME" else CHANGED_LIST="$FILENAME" fi fi done echo "version_changed=$VERSION_CHANGED" >> $GITHUB_OUTPUT echo "changed_files=$CHANGED_LIST" >> $GITHUB_OUTPUT
  • echo "::error::API proposal version changed in: ${{ steps.version_check.outputs.changed_files }}" echo "To unblock, comment '/api-proposal-change-required' on the PR." exit 1
View raw YAML
name: API Proposal Version Check

on:
  pull_request:
    branches:
      - main
      - 'release/*'
    paths:
      - 'src/vscode-dts/vscode.proposed.*.d.ts'
  issue_comment:
    types: [created]

permissions:
  contents: read
  pull-requests: write
  actions: write

concurrency:
  group: api-proposal-${{ github.event.pull_request.number || github.event.issue.number }}
  cancel-in-progress: true

jobs:
  check-version-changes:
    name: Check API Proposal Version Changes
    # Run on PR events, or on issue_comment if it's on a PR and contains the override command
    if: |
      github.event_name == 'pull_request' ||
      (github.event_name == 'issue_comment' &&
       github.event.issue.pull_request &&
       contains(github.event.comment.body, '/api-proposal-change-required') &&
       (github.event.comment.author_association == 'OWNER' ||
        github.event.comment.author_association == 'MEMBER' ||
        github.event.comment.author_association == 'COLLABORATOR'))
    runs-on: ubuntu-latest
    steps:
      - name: Get PR info
        id: pr_info
        uses: actions/github-script@v8
        with:
          script: |
            let prNumber, headSha, baseSha;

            if (context.eventName === 'pull_request') {
              prNumber = context.payload.pull_request.number;
              headSha = context.payload.pull_request.head.sha;
              baseSha = context.payload.pull_request.base.sha;
            } else {
              // issue_comment event - need to fetch PR details
              prNumber = context.payload.issue.number;
              const { data: pr } = await github.rest.pulls.get({
                owner: context.repo.owner,
                repo: context.repo.repo,
                pull_number: prNumber
              });
              headSha = pr.head.sha;
              baseSha = pr.base.sha;
            }

            core.setOutput('number', prNumber);
            core.setOutput('head_sha', headSha);
            core.setOutput('base_sha', baseSha);

      - name: Check for override comment
        id: check_override
        uses: actions/github-script@v8
        with:
          script: |
            const prNumber = ${{ steps.pr_info.outputs.number }};
            const { data: comments } = await github.rest.issues.listComments({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: prNumber
            });

            // Only accept overrides from trusted users (repo members/collaborators)
            const trustedAssociations = ['OWNER', 'MEMBER', 'COLLABORATOR'];
            let overrideComment = null;
            const untrustedOverrides = [];

            comments.forEach((comment, index) => {
              const hasOverrideText = comment.body.includes('/api-proposal-change-required');
              const isTrusted = trustedAssociations.includes(comment.author_association);
              console.log(`Comment ${index + 1}:`);
              console.log(`  Author: ${comment.user.login}`);
              console.log(`  Author association: ${comment.author_association}`);
              console.log(`  Created at: ${comment.created_at}`);
              console.log(`  Contains override command: ${hasOverrideText}`);
              console.log(`  Author is trusted: ${isTrusted}`);
              console.log(`  Would be valid override: ${hasOverrideText && isTrusted}`);

              if (hasOverrideText) {
                if (isTrusted && !overrideComment) {
                  overrideComment = comment;
                } else if (!isTrusted) {
                  untrustedOverrides.push(comment);
                }
              }
            });

            if (overrideComment) {
              console.log(`✅ Override comment FOUND`);
              console.log(`  Comment ID: ${overrideComment.id}`);
              console.log(`  Author: ${overrideComment.user.login}`);
              console.log(`  Association: ${overrideComment.author_association}`);
              console.log(`  Created at: ${overrideComment.created_at}`);
              core.setOutput('override_found', 'true');
              core.setOutput('override_user', overrideComment.user.login);
            } else {
              if (untrustedOverrides.length > 0) {
                console.log(`⚠️ Found ${untrustedOverrides.length} override comment(s) from UNTRUSTED user(s):`);
                untrustedOverrides.forEach((comment, index) => {
                  console.log(`  Untrusted override ${index + 1}:`);
                  console.log(`    Author: ${comment.user.login}`);
                  console.log(`    Association: ${comment.author_association}`);
                  console.log(`    Created at: ${comment.created_at}`);
                  console.log(`    Comment ID: ${comment.id}`);
                });
                console.log(`  Trusted associations are: ${trustedAssociations.join(', ')}`);
              }
              console.log('❌ No valid override comment found');
              core.setOutput('override_found', 'false');
            }

      # If triggered by the override comment, re-run the failed workflow to update its status
      # Only allow trusted users to trigger re-runs to prevent spam
      - name: Re-run failed workflow on override
        if: |
          steps.check_override.outputs.override_found == 'true' &&
          github.event_name == 'issue_comment' &&
          (github.event.comment.author_association == 'OWNER' ||
           github.event.comment.author_association == 'MEMBER' ||
           github.event.comment.author_association == 'COLLABORATOR')
        uses: actions/github-script@v8
        with:
          script: |
            const headSha = '${{ steps.pr_info.outputs.head_sha }}';
            console.log(`Override comment found by ${{ steps.check_override.outputs.override_user }}`);
            console.log('API proposal version change has been acknowledged.');

            // Find the failed workflow run for this PR's head SHA
            const { data: runs } = await github.rest.actions.listWorkflowRuns({
              owner: context.repo.owner,
              repo: context.repo.repo,
              workflow_id: 'api-proposal-version-check.yml',
              head_sha: headSha,
              status: 'completed',
              per_page: 10
            });

            // Find the most recent failed run
            const failedRun = runs.workflow_runs.find(run =>
              run.conclusion === 'failure' && run.event === 'pull_request'
            );

            if (failedRun) {
              console.log(`Re-running failed workflow run ${failedRun.id}`);
              await github.rest.actions.reRunWorkflow({
                owner: context.repo.owner,
                repo: context.repo.repo,
                run_id: failedRun.id
              });
              console.log('Workflow re-run triggered successfully');
            } else {
              console.log('No failed pull_request workflow run found to re-run');
              // The check will pass on this run since override exists
            }

      - name: Pass on override comment
        if: steps.check_override.outputs.override_found == 'true'
        run: |
          echo "Override comment found by ${{ steps.check_override.outputs.override_user }}"
          echo "API proposal version change has been acknowledged."

      # Only continue checking if no override found
      - name: Checkout repository
        if: steps.check_override.outputs.override_found != 'true'
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Check for version changes
        if: steps.check_override.outputs.override_found != 'true'
        id: version_check
        env:
          HEAD_SHA: ${{ steps.pr_info.outputs.head_sha }}
          BASE_SHA: ${{ steps.pr_info.outputs.base_sha }}
        run: |
          set -e

          # Use merge-base to get accurate diff of what the PR actually changes
          MERGE_BASE=$(git merge-base "$BASE_SHA" "$HEAD_SHA")
          echo "Merge base: $MERGE_BASE"

          # Get the list of changed proposed API files (diff against merge-base)
          CHANGED_FILES=$(git diff --name-only "$MERGE_BASE" "$HEAD_SHA" -- 'src/vscode-dts/vscode.proposed.*.d.ts' || true)

          if [ -z "$CHANGED_FILES" ]; then
            echo "No proposed API files changed"
            echo "version_changed=false" >> $GITHUB_OUTPUT
            exit 0
          fi

          echo "Changed proposed API files:"
          echo "$CHANGED_FILES"

          VERSION_CHANGED="false"
          CHANGED_LIST=""

          for FILE in $CHANGED_FILES; do
            # Check if file exists in head
            if ! git cat-file -e "$HEAD_SHA:$FILE" 2>/dev/null; then
              echo "File $FILE was deleted, skipping version check"
              continue
            fi

            # Get version from head (current PR)
            HEAD_VERSION=$(git show "$HEAD_SHA:$FILE" | grep -E '^// version: [0-9]+' | sed 's/.*version: //' || echo "")

            # Get version from merge-base (what the PR is based on)
            BASE_VERSION=$(git show "$MERGE_BASE:$FILE" 2>/dev/null | grep -E '^// version: [0-9]+' | sed 's/.*version: //' || echo "")

            echo "File: $FILE"
            echo "  Base version: ${BASE_VERSION:-'(none)'}"
            echo "  Head version: ${HEAD_VERSION:-'(none)'}"

            # Check if version was added or changed
            if [ -n "$HEAD_VERSION" ] && [ "$HEAD_VERSION" != "$BASE_VERSION" ]; then
              echo "  -> Version changed!"
              VERSION_CHANGED="true"
              FILENAME=$(basename "$FILE")
              if [ -n "$CHANGED_LIST" ]; then
                CHANGED_LIST="$CHANGED_LIST, $FILENAME"
              else
                CHANGED_LIST="$FILENAME"
              fi
            fi
          done

          echo "version_changed=$VERSION_CHANGED" >> $GITHUB_OUTPUT
          echo "changed_files=$CHANGED_LIST" >> $GITHUB_OUTPUT

      - name: Post warning comment
        if: steps.check_override.outputs.override_found != 'true' && steps.version_check.outputs.version_changed == 'true'
        uses: actions/github-script@v8
        with:
          script: |
            const prNumber = ${{ steps.pr_info.outputs.number }};
            const changedFiles = '${{ steps.version_check.outputs.changed_files }}';

            // Check if we already posted a warning comment
            const { data: comments } = await github.rest.issues.listComments({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: prNumber
            });

            const marker = '<!-- api-proposal-version-warning -->';
            const existingComment = comments.find(comment =>
              comment.body.includes(marker)
            );

            const body = `${marker}
            ## ⚠️ API Proposal Version Change Detected

            The following proposed API files have version changes: **${changedFiles}**

            API proposal version changes should only be used when maintaining compatibility is not possible. Consider keeping the version as is and maintaining backward compatibility.

            **Any version changes must be adopted by the consuming extensions before the next insiders for the extension to work.**

            ---

            If the version change is required, comment \`/api-proposal-change-required\` to unblock this check and acknowledge that you will update any critical consuming extensions (Copilot Chat).`;

            if (existingComment) {
              await github.rest.issues.updateComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: existingComment.id,
                body: body
              });
              console.log('Updated existing warning comment');
            } else {
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: prNumber,
                body: body
              });
              console.log('Posted new warning comment');
            }

      - name: Fail if version changed without override
        if: steps.check_override.outputs.override_found != 'true' && steps.version_check.outputs.version_changed == 'true'
        run: |
          echo "::error::API proposal version changed in: ${{ steps.version_check.outputs.changed_files }}"
          echo "To unblock, comment '/api-proposal-change-required' on the PR."
          exit 1
copilot-setup-steps .github/workflows/copilot-setup-steps.yml
Triggers
workflow_dispatch, push, pull_request
Runs on
vscode-large-runners
Jobs
copilot-setup-steps
Commands
  • set -e # Start X server ./build/azure-pipelines/linux/apt-retry.sh sudo apt-get update ./build/azure-pipelines/linux/apt-retry.sh sudo apt-get install -y pkg-config \ xvfb \ libgtk-3-0 \ libxkbfile-dev \ libkrb5-dev \ libgbm1 \ rpm sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb sudo chmod +x /etc/init.d/xvfb sudo update-rc.d xvfb defaults sudo service xvfb start
  • mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts linux x64 $(node -p process.arch) > .build/packagelockhash
  • tar -xzf .build/node_modules_cache/cache.tgz
  • set -e for i in {1..5}; do # try 5 times npm ci && break if [ $i -eq 5 ]; then echo "Npm install failed too many times" >&2 exit 1 fi echo "Npm install failed $i, trying again..." done
  • set -e source ./build/azure-pipelines/linux/setup-env.sh for i in {1..5}; do # try 5 times npm ci && break if [ $i -eq 5 ]; then echo "Npm install failed too many times" >&2 exit 1 fi echo "Npm install failed $i, trying again..." done
  • set -e node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt mkdir -p .build/node_modules_cache tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
  • mkdir -p .build
  • node build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts > .build/builtindepshash
View raw YAML
name: "Copilot Setup Steps"

# Automatically run the setup steps when they are changed to allow for easy validation, and
# allow manual testing through the repository's "Actions" tab
on:
  workflow_dispatch:
  push:
    paths:
      - .github/workflows/copilot-setup-steps.yml
  pull_request:
    paths:
      - .github/workflows/copilot-setup-steps.yml

jobs:
  # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
  copilot-setup-steps:
    runs-on: vscode-large-runners

    # Set the permissions to the lowest permissions possible needed for your steps.
    # Copilot will be given its own token for its operations.
    permissions:
      # If you want to clone the repository as part of your setup steps, for example to install dependencies, you'll need the `contents: read` permission. If you don't clone the repository in your setup steps, Copilot will do this for you automatically after the steps complete.
      contents: read

    # You can define any steps you want, and they will run before the agent starts.
    # If you do not check out your code, Copilot will do this for you.
    steps:
      - name: Checkout microsoft/vscode
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc

      - name: Setup system services
        run: |
          set -e
          # Start X server
          ./build/azure-pipelines/linux/apt-retry.sh sudo apt-get update
          ./build/azure-pipelines/linux/apt-retry.sh sudo apt-get install -y pkg-config \
            xvfb \
            libgtk-3-0 \
            libxkbfile-dev \
            libkrb5-dev \
            libgbm1 \
            rpm
          sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb
          sudo chmod +x /etc/init.d/xvfb
          sudo update-rc.d xvfb defaults
          sudo service xvfb start

      - name: Prepare node_modules cache key
        run: mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts linux x64 $(node -p process.arch) > .build/packagelockhash

      - name: Restore node_modules cache
        id: cache-node-modules
        uses: actions/cache/restore@v5
        with:
          path: .build/node_modules_cache
          key: "node_modules-linux-${{ hashFiles('.build/packagelockhash') }}"

      - name: Extract node_modules cache
        if: steps.cache-node-modules.outputs.cache-hit == 'true'
        run: tar -xzf .build/node_modules_cache/cache.tgz

      - name: Install build dependencies
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        working-directory: build
        run: |
          set -e

          for i in {1..5}; do # try 5 times
            npm ci && break
            if [ $i -eq 5 ]; then
              echo "Npm install failed too many times" >&2
              exit 1
            fi
            echo "Npm install failed $i, trying again..."
          done
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Install dependencies
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e

          source ./build/azure-pipelines/linux/setup-env.sh

          for i in {1..5}; do # try 5 times
            npm ci && break
            if [ $i -eq 5 ]; then
              echo "Npm install failed too many times" >&2
              exit 1
            fi
            echo "Npm install failed $i, trying again..."
          done
        env:
          npm_config_arch: x64
          VSCODE_ARCH: x64
          ELECTRON_SKIP_BINARY_DOWNLOAD: 1
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Create node_modules archive
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e
          node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt
          mkdir -p .build/node_modules_cache
          tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt

      - name: Create .build folder
        run: mkdir -p .build

      - name: Prepare built-in extensions cache key
        run: node build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts > .build/builtindepshash

      - name: Restore built-in extensions cache
        id: cache-builtin-extensions
        uses: actions/cache/restore@v5
        with:
          enableCrossOsArchive: true
          path: .build/builtInExtensions
          key: "builtin-extensions-${{ hashFiles('.build/builtindepshash') }}"

      - name: Download built-in extensions
        if: steps.cache-builtin-extensions.outputs.cache-hit != 'true'
        run: node build/lib/builtInExtensions.ts
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      # - name: Transpile client and extensions
      #   run: npm run gulp transpile-client-esbuild transpile-extensions

      - name: Download Electron and Playwright
        run: |
          set -e

          for i in {1..3}; do # try 3 times (matching retryCountOnTaskFailure: 3)
            if npm exec -- npm-run-all2 -lp "electron x64" "playwright-install"; then
              echo "Download successful on attempt $i"
              break
            fi

            if [ $i -eq 3 ]; then
              echo "Download failed after 3 attempts" >&2
              exit 1
            fi

            echo "Download failed on attempt $i, retrying..."
            sleep 5 # optional: add a small delay between retries
          done
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      # - name: 🧪 Run unit tests (Electron)
      #   if: ${{ inputs.electron_tests }}
      #   timeout-minutes: 15
      #   run: ./scripts/test.sh --tfs "Unit Tests"
      #   env:
      #     DISPLAY: ":10"

      # - name: 🧪 Run unit tests (node.js)
      #   if: ${{ inputs.electron_tests }}
      #   timeout-minutes: 15
      #   run: npm run test-node

      # - name: 🧪 Run unit tests (Browser, Chromium)
      #   if: ${{ inputs.browser_tests }}
      #   timeout-minutes: 30
      #   run: npm run test-browser-no-install -- --browser chromium --tfs "Browser Unit Tests"
      #   env:
      #     DEBUG: "*browser*"

      # - name: Build integration tests
      #   run: |
      #     set -e
      #     npm run gulp \
      #       compile-extension:configuration-editing \
      #       compile-extension:css-language-features-server \
      #       compile-extension:emmet \
      #       compile-extension:git \
      #       compile-extension:github-authentication \
      #       compile-extension:html-language-features-server \
      #       compile-extension:ipynb \
      #       compile-extension:notebook-renderers \
      #       compile-extension:json-language-features-server \
      #       compile-extension:markdown-language-features \
      #       compile-extension-media \
      #       compile-extension:microsoft-authentication \
      #       compile-extension:typescript-language-features \
      #       compile-extension:vscode-api-tests \
      #       compile-extension:vscode-colorize-tests \
      #       compile-extension:vscode-colorize-perf-tests \
      #       compile-extension:vscode-test-resolver

      # - name: 🧪 Run integration tests (Electron)
      #   if: ${{ inputs.electron_tests }}
      #   timeout-minutes: 20
      #   run: ./scripts/test-integration.sh --tfs "Integration Tests"
      #   env:
      #     DISPLAY: ":10"

      # - name: 🧪 Run integration tests (Browser, Chromium)
      #   if: ${{ inputs.browser_tests }}
      #   timeout-minutes: 20
      #   run: ./scripts/test-web-integration.sh --browser chromium

      # - name: 🧪 Run integration tests (Remote)
      #   if: ${{ inputs.remote_tests }}
      #   timeout-minutes: 20
      #   run: ./scripts/test-remote-integration.sh
      #   env:
      #     DISPLAY: ":10"

      # - name: Compile smoke tests
      #   working-directory: test/smoke
      #   run: npm run compile

      # - name: Compile extensions for smoke tests
      #   run: npm run gulp compile-extension-media

      # - name: Diagnostics before smoke test run (processes, max_user_watches, number of opened file handles)
      #   run: |
      #     set -e
      #     ps -ef
      #     cat /proc/sys/fs/inotify/max_user_watches
      #     lsof | wc -l
      #   continue-on-error: true
      #   if: always()

      # - name: 🧪 Run smoke tests (Electron)
      #   if: ${{ inputs.electron_tests }}
      #   timeout-minutes: 20
      #   run: npm run smoketest-no-compile -- --tracing
      #   env:
      #     DISPLAY: ":10"

      # - name: 🧪 Run smoke tests (Browser, Chromium)
      #   if: ${{ inputs.browser_tests }}
      #   timeout-minutes: 20
      #   run: npm run smoketest-no-compile -- --web --tracing --headless

      # - name: 🧪 Run smoke tests (Remote)
      #   if: ${{ inputs.remote_tests }}
      #   timeout-minutes: 20
      #   run: npm run smoketest-no-compile -- --remote --tracing
      #   env:
      #     DISPLAY: ":10"

      # - name: Diagnostics after smoke test run (processes, max_user_watches, number of opened file handles)
      #   run: |
      #     set -e
      #     ps -ef
      #     cat /proc/sys/fs/inotify/max_user_watches
      #     lsof | wc -l
      #   continue-on-error: true
      #   if: always()
monaco-editor perms .github/workflows/monaco-editor.yml
Triggers
push, pull_request
Runs on
ubuntu-latest
Jobs
main
Commands
  • echo "value=$(node build/azure-pipelines/common/computeNodeModulesCacheKey.ts)" >> $GITHUB_OUTPUT
  • echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
  • sudo apt update sudo apt install -y libxkbfile-dev pkg-config libkrb5-dev libxss1
  • npm ci
  • npm run playwright-install
  • npm run monaco-compile-check
  • npm run gulp editor-distro
  • npm run esm-check
View raw YAML
name: Monaco Editor checks

on:
  push:
    branches:
      - main
      - release/*
  pull_request:
    branches:
      - main
      - release/*
permissions: {}

jobs:
  main:
    name: Monaco Editor checks
    runs-on: ubuntu-latest
    timeout-minutes: 40
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/checkout@v6
        with:
          persist-credentials: false

      - uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc

      - name: Compute node modules cache key
        id: nodeModulesCacheKey
        run: echo "value=$(node build/azure-pipelines/common/computeNodeModulesCacheKey.ts)" >> $GITHUB_OUTPUT
      - name: Cache node modules
        id: cacheNodeModules
        uses: actions/cache@v5
        with:
          path: "**/node_modules"
          key: ${{ runner.os }}-cacheNodeModules20-${{ steps.nodeModulesCacheKey.outputs.value }}
          restore-keys: ${{ runner.os }}-cacheNodeModules20-
      - name: Get npm cache directory path
        id: npmCacheDirPath
        if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
        run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
      - name: Cache npm directory
        if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
        uses: actions/cache@v5
        with:
          path: ${{ steps.npmCacheDirPath.outputs.dir }}
          key: ${{ runner.os }}-npmCacheDir-${{ steps.nodeModulesCacheKey.outputs.value }}
          restore-keys: ${{ runner.os }}-npmCacheDir-
      - name: Install system dependencies
        if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
        run: |
          sudo apt update
          sudo apt install -y libxkbfile-dev pkg-config libkrb5-dev libxss1
      - name: Execute npm
        if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }}
        env:
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
          ELECTRON_SKIP_BINARY_DOWNLOAD: 1
        run: |
          npm ci

      - name: Download Playwright
        run: npm run playwright-install

      - name: Run Monaco Editor Checks
        run: npm run monaco-compile-check

      - name: Editor Distro & ESM
        run: npm run gulp editor-distro

      - name: Editor ESM sources check
        working-directory: ./test/monaco
        run: npm run esm-check

      - name: Typings validation prep
        run: |
          mkdir typings-test

      - name: Typings validation
        working-directory: ./typings-test
        run: |
          npm init -yp
          ../node_modules/.bin/tsc --init
          echo "import '../out-monaco-editor-core';" > a.ts
          ../node_modules/.bin/tsc --noEmit

      - name: Package Editor with Webpack
        working-directory: ./test/monaco
        run: npm run bundle-webpack

      - name: Compile Editor Tests
        working-directory: ./test/monaco
        run: npm run compile

      - name: Run Editor Tests
        timeout-minutes: 5
        working-directory: ./test/monaco
        run: npm run test
no-engineering-system-changes perms .github/workflows/no-engineering-system-changes.yml
Triggers
pull_request
Runs on
ubuntu-latest
Jobs
main
Actions
trilom/file-changes-action, octokit/request-action
Commands
  • if cat $HOME/files.json | jq -e 'any(test("^\\.github\\/workflows\\/|^build\\/|package\\.json$"))' > /dev/null; then echo "engineering_systems_modified=true" >> $GITHUB_OUTPUT echo "Engineering systems were modified in this PR" else echo "engineering_systems_modified=false" >> $GITHUB_OUTPUT echo "No engineering systems were modified in this PR" fi
  • # Allow the vs-code-engineering bot ONLY when package.json is the # sole changed file and the diff exclusively touches the "distro" field. ONLY_PKG=$(jq -e '. == ["package.json"]' "$HOME/files.json" > /dev/null 2>&1 && echo true || echo false) if [[ "$ONLY_PKG" != "true" ]]; then echo "Bot modified files beyond package.json — not allowed" echo "allowed=false" >> $GITHUB_OUTPUT exit 0 fi DIFF=$(gh pr diff ${{ github.event.pull_request.number }} --repo ${{ github.repository }}) || { echo "Failed to fetch PR diff — not allowed" echo "allowed=false" >> $GITHUB_OUTPUT exit 0 } CHANGED_LINES=$(echo "$DIFF" | grep -E '^[+-]' | grep -vE '^(\+\+\+|---)' | wc -l) DISTRO_LINES=$(echo "$DIFF" | grep -cE '^[+-][[:space:]]*"distro"[[:space:]]*:' || true) if [[ "$CHANGED_LINES" -eq 2 && "$DISTRO_LINES" -eq 2 ]]; then echo "Distro-only update by bot — allowing" echo "allowed=true" >> $GITHUB_OUTPUT else echo "Bot changed more than the distro field — not allowed" echo "allowed=false" >> $GITHUB_OUTPUT fi
  • echo "Copilot is not allowed to modify .github/workflows, build folder files, or package.json files." echo "If you need to update engineering systems, please do so manually or through authorized means." exit 1
  • echo "user: ${{ github.event.pull_request.user.login }}" echo "role: ${{ fromJson(steps.get_permissions.outputs.data).permission }}" echo "is dependabot: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}" echo "should_run: ${{ !contains(fromJson('["admin", "maintain", "write"]'), fromJson(steps.get_permissions.outputs.data).permission) }}" echo "should_run=${{ !contains(fromJson('["admin", "maintain", "write"]'), fromJson(steps.get_permissions.outputs.data).permission) && github.event.pull_request.user.login != 'dependabot[bot]' }}" >> $GITHUB_OUTPUT
  • echo "Changes to .github/workflows/, build/ folder files, or package.json files aren't allowed in PRs." exit 1
View raw YAML
name: Prevent engineering system changes in PRs

on: pull_request
permissions: {}

jobs:
  main:
    name: Prevent engineering system changes in PRs
    runs-on: ubuntu-latest
    steps:
      - name: Get file changes
        uses: trilom/file-changes-action@a6ca26c14274c33b15e6499323aac178af06ad4b # v1.2.4
        id: file_changes
      - name: Check if engineering systems were modified
        id: engineering_systems_check
        run: |
          if cat $HOME/files.json | jq -e 'any(test("^\\.github\\/workflows\\/|^build\\/|package\\.json$"))' > /dev/null; then
            echo "engineering_systems_modified=true" >> $GITHUB_OUTPUT
            echo "Engineering systems were modified in this PR"
          else
            echo "engineering_systems_modified=false" >> $GITHUB_OUTPUT
            echo "No engineering systems were modified in this PR"
          fi
      - name: Allow automated distro updates
        id: distro_exception
        if: ${{ steps.engineering_systems_check.outputs.engineering_systems_modified == 'true' && github.event.pull_request.user.login == 'vs-code-engineering[bot]' }}
        run: |
          # Allow the vs-code-engineering bot ONLY when package.json is the
          # sole changed file and the diff exclusively touches the "distro" field.
          ONLY_PKG=$(jq -e '. == ["package.json"]' "$HOME/files.json" > /dev/null 2>&1 && echo true || echo false)
          if [[ "$ONLY_PKG" != "true" ]]; then
            echo "Bot modified files beyond package.json — not allowed"
            echo "allowed=false" >> $GITHUB_OUTPUT
            exit 0
          fi

          DIFF=$(gh pr diff ${{ github.event.pull_request.number }} --repo ${{ github.repository }}) || {
            echo "Failed to fetch PR diff — not allowed"
            echo "allowed=false" >> $GITHUB_OUTPUT
            exit 0
          }
          CHANGED_LINES=$(echo "$DIFF" | grep -E '^[+-]' | grep -vE '^(\+\+\+|---)' | wc -l)
          DISTRO_LINES=$(echo "$DIFF" | grep -cE '^[+-][[:space:]]*"distro"[[:space:]]*:' || true)

          if [[ "$CHANGED_LINES" -eq 2 && "$DISTRO_LINES" -eq 2 ]]; then
            echo "Distro-only update by bot — allowing"
            echo "allowed=true" >> $GITHUB_OUTPUT
          else
            echo "Bot changed more than the distro field — not allowed"
            echo "allowed=false" >> $GITHUB_OUTPUT
          fi
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Prevent Copilot from modifying engineering systems
        if: ${{ steps.engineering_systems_check.outputs.engineering_systems_modified == 'true' && steps.distro_exception.outputs.allowed != 'true' && github.event.pull_request.user.login == 'Copilot' }}
        run: |
          echo "Copilot is not allowed to modify .github/workflows, build folder files, or package.json files."
          echo "If you need to update engineering systems, please do so manually or through authorized means."
          exit 1
      - uses: octokit/request-action@b91aabaa861c777dcdb14e2387e30eddf04619ae # v3.0.0
        id: get_permissions
        if: ${{ steps.engineering_systems_check.outputs.engineering_systems_modified == 'true' && steps.distro_exception.outputs.allowed != 'true' && github.event.pull_request.user.login != 'Copilot' }}
        with:
          route: GET /repos/microsoft/vscode/collaborators/${{ github.event.pull_request.user.login }}/permission
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Set control output variable
        id: control
        if: ${{ steps.engineering_systems_check.outputs.engineering_systems_modified == 'true' && steps.distro_exception.outputs.allowed != 'true' && github.event.pull_request.user.login != 'Copilot' }}
        run: |
          echo "user: ${{ github.event.pull_request.user.login }}"
          echo "role: ${{ fromJson(steps.get_permissions.outputs.data).permission }}"
          echo "is dependabot: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}"
          echo "should_run: ${{ !contains(fromJson('["admin", "maintain", "write"]'), fromJson(steps.get_permissions.outputs.data).permission) }}"
          echo "should_run=${{ !contains(fromJson('["admin", "maintain", "write"]'), fromJson(steps.get_permissions.outputs.data).permission) && github.event.pull_request.user.login != 'dependabot[bot]' }}" >> $GITHUB_OUTPUT
      - name: Check for engineering system changes
        if: ${{ steps.engineering_systems_check.outputs.engineering_systems_modified == 'true' && steps.distro_exception.outputs.allowed != 'true' && steps.control.outputs.should_run == 'true' }}
        run: |
          echo "Changes to .github/workflows/, build/ folder files, or package.json files aren't allowed in PRs."
          exit 1
pr perms .github/workflows/pr.yml
Triggers
pull_request
Runs on
ubuntu-22.04
Jobs
compile, linux-cli-tests, linux-electron-tests, linux-browser-tests, linux-remote-tests, macos-electron-tests, macos-browser-tests, macos-remote-tests, windows-electron-tests, windows-browser-tests, windows-remote-tests
Commands
  • mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts compile $(node -p process.arch) > .build/packagelockhash
  • tar -xzf .build/node_modules_cache/cache.tgz
  • sudo apt update -y && sudo apt install -y build-essential pkg-config libx11-dev libx11-xcb-dev libxkbfile-dev libnotify-bin libkrb5-dev
  • set -e for i in {1..5}; do # try 5 times npm ci && break if [ $i -eq 5 ]; then echo "Npm install failed too many times" >&2 exit 1 fi echo "Npm install failed $i, trying again..." done
  • set -e node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt mkdir -p .build/node_modules_cache tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
  • npm run typecheck
  • npm exec -- npm-run-all2 -lp core-ci hygiene eslint valid-layers-check define-class-fields-check vscode-dts-compile-check tsec-compile-check test-build-scripts
  • node build/lib/checkCyclicDependencies.ts out-build
View raw YAML
name: Code OSS

on:
  pull_request:
    branches:
      - main
      - 'release/*'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read

env:
  VSCODE_QUALITY: 'oss'

jobs:
  compile:
    name: Compile & Hygiene
    runs-on: ubuntu-22.04
    steps:
      - name: Checkout microsoft/vscode
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc

      - name: Prepare node_modules cache key
        run: mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts compile $(node -p process.arch) > .build/packagelockhash

      - name: Restore node_modules cache
        id: cache-node-modules
        uses: actions/cache/restore@v5
        with:
          path: .build/node_modules_cache
          key: "node_modules-compile-${{ hashFiles('.build/packagelockhash') }}"

      - name: Extract node_modules cache
        if: steps.cache-node-modules.outputs.cache-hit == 'true'
        run: tar -xzf .build/node_modules_cache/cache.tgz

      - name: Install build tools
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: sudo apt update -y && sudo apt install -y build-essential pkg-config libx11-dev libx11-xcb-dev libxkbfile-dev libnotify-bin libkrb5-dev

      - name: Install dependencies
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e

          for i in {1..5}; do # try 5 times
            npm ci && break
            if [ $i -eq 5 ]; then
              echo "Npm install failed too many times" >&2
              exit 1
            fi
            echo "Npm install failed $i, trying again..."
          done
        env:
          ELECTRON_SKIP_BINARY_DOWNLOAD: 1
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Create node_modules archive
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e
          node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt
          mkdir -p .build/node_modules_cache
          tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt

      - name: Type check /build/ scripts
        run: npm run typecheck
        working-directory: build

      - name: Compile & Hygiene
        run: npm exec -- npm-run-all2 -lp core-ci hygiene eslint valid-layers-check define-class-fields-check vscode-dts-compile-check tsec-compile-check test-build-scripts
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Check cyclic dependencies
        run: node build/lib/checkCyclicDependencies.ts out-build

  linux-cli-tests:
    name: Linux
    uses: ./.github/workflows/pr-linux-cli-test.yml
    with:
      job_name: CLI
      rustup_toolchain: 1.88

  linux-electron-tests:
    name: Linux
    uses: ./.github/workflows/pr-linux-test.yml
    with:
      job_name: Electron
      electron_tests: true

  linux-browser-tests:
    name: Linux
    uses: ./.github/workflows/pr-linux-test.yml
    with:
      job_name: Browser
      browser_tests: true

  linux-remote-tests:
    name: Linux
    uses: ./.github/workflows/pr-linux-test.yml
    with:
      job_name: Remote
      remote_tests: true

  macos-electron-tests:
    name: macOS
    uses: ./.github/workflows/pr-darwin-test.yml
    with:
      job_name: Electron
      electron_tests: true

  macos-browser-tests:
    name: macOS
    uses: ./.github/workflows/pr-darwin-test.yml
    with:
      job_name: Browser
      browser_tests: true

  macos-remote-tests:
    name: macOS
    uses: ./.github/workflows/pr-darwin-test.yml
    with:
      job_name: Remote
      remote_tests: true

  windows-electron-tests:
    name: Windows
    uses: ./.github/workflows/pr-win32-test.yml
    with:
      job_name: Electron
      electron_tests: true

  windows-browser-tests:
    name: Windows
    uses: ./.github/workflows/pr-win32-test.yml
    with:
      job_name: Browser
      browser_tests: true

  windows-remote-tests:
    name: Windows
    uses: ./.github/workflows/pr-win32-test.yml
    with:
      job_name: Remote
      remote_tests: true
pr-darwin-test .github/workflows/pr-darwin-test.yml
Triggers
workflow_call
Runs on
macos-14-xlarge
Jobs
macOS-test
Commands
  • mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts darwin $VSCODE_ARCH $(node -p process.arch) > .build/packagelockhash
  • tar -xzf .build/node_modules_cache/cache.tgz
  • set -e c++ --version xcode-select -print-path python3 -m pip install --break-system-packages setuptools for i in {1..5}; do # try 5 times npm ci && break if [ $i -eq 5 ]; then echo "Npm install failed too many times" >&2 exit 1 fi echo "Npm install failed $i, trying again..." done
  • set -e node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt mkdir -p .build/node_modules_cache tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
  • mkdir -p .build
  • node build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts > .build/builtindepshash
  • node build/lib/builtInExtensions.ts
  • npm run gulp transpile-client-esbuild transpile-extensions
View raw YAML
on:
  workflow_call:
    inputs:
      job_name:
        type: string
        required: true
      electron_tests:
        type: boolean
        default: false
      browser_tests:
        type: boolean
        default: false
      remote_tests:
        type: boolean
        default: false

jobs:
  macOS-test:
    name: ${{ inputs.job_name }}
    runs-on: macos-14-xlarge
    env:
      ARTIFACT_NAME: ${{ (inputs.electron_tests && 'electron') || (inputs.browser_tests && 'browser') || (inputs.remote_tests && 'remote') || 'unknown' }}
      NPM_ARCH: arm64
      VSCODE_ARCH: arm64
    steps:
      - name: Checkout microsoft/vscode
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc

      - name: Prepare node_modules cache key
        run: mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts darwin $VSCODE_ARCH $(node -p process.arch) > .build/packagelockhash

      - name: Restore node_modules cache
        id: cache-node-modules
        uses: actions/cache/restore@v5
        with:
          path: .build/node_modules_cache
          key: "node_modules-macos-${{ hashFiles('.build/packagelockhash') }}"

      - name: Extract node_modules cache
        if: steps.cache-node-modules.outputs.cache-hit == 'true'
        run: tar -xzf .build/node_modules_cache/cache.tgz

      - name: Install dependencies
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e
          c++ --version
          xcode-select -print-path
          python3 -m pip install --break-system-packages setuptools

          for i in {1..5}; do # try 5 times
            npm ci && break
            if [ $i -eq 5 ]; then
              echo "Npm install failed too many times" >&2
              exit 1
            fi
            echo "Npm install failed $i, trying again..."
          done
        env:
          npm_config_arch: ${{ env.NPM_ARCH }}
          VSCODE_ARCH: ${{ env.VSCODE_ARCH }}
          ELECTRON_SKIP_BINARY_DOWNLOAD: 1
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          # Avoid using dlopen to load Kerberos on macOS which can cause missing libraries
          # https://github.com/mongodb-js/kerberos/commit/04044d2814ad1d01e77f1ce87f26b03d86692cf2
          # flipped the default to support legacy linux distros which shouldn't happen
          # on macOS.
          GYP_DEFINES: "kerberos_use_rtld=false"

      - name: Create node_modules archive
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e
          node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt
          mkdir -p .build/node_modules_cache
          tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt

      - name: Create .build folder
        run: mkdir -p .build

      - name: Prepare built-in extensions cache key
        run: node build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts > .build/builtindepshash

      - name: Restore built-in extensions cache
        id: cache-builtin-extensions
        uses: actions/cache/restore@v5
        with:
          enableCrossOsArchive: true
          path: .build/builtInExtensions
          key: "builtin-extensions-${{ hashFiles('.build/builtindepshash') }}"

      - name: Download built-in extensions
        if: steps.cache-builtin-extensions.outputs.cache-hit != 'true'
        run: node build/lib/builtInExtensions.ts
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Transpile client and extensions
        run: npm run gulp transpile-client-esbuild transpile-extensions

      - name: Download Electron and Playwright
        run: |
          set -e

          for i in {1..3}; do # try 3 times (matching retryCountOnTaskFailure: 3)
            if npm exec -- npm-run-all2 -lp "electron ${{ env.VSCODE_ARCH }}" "playwright-install"; then
              echo "Download successful on attempt $i"
              break
            fi

            if [ $i -eq 3 ]; then
              echo "Download failed after 3 attempts" >&2
              exit 1
            fi

            echo "Download failed on attempt $i, retrying..."
            sleep 5 # optional: add a small delay between retries
          done
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: 🧪 Run unit tests (Electron)
        if: ${{ inputs.electron_tests }}
        timeout-minutes: 15
        run: ./scripts/test.sh --tfs "Unit Tests"

      - name: 🧪 Run unit tests (node.js)
        if: ${{ inputs.electron_tests }}
        timeout-minutes: 15
        run: npm run test-node

      - name: 🧪 Run unit tests (Browser, Webkit)
        if: ${{ inputs.browser_tests }}
        timeout-minutes: 30
        run: npm run test-browser-no-install -- --browser webkit --tfs "Browser Unit Tests"
        env:
          DEBUG: "*browser*"

      - name: Build integration tests
        run: |
          set -e
          npm run gulp \
            compile-extension:configuration-editing \
            compile-extension:css-language-features-server \
            compile-extension:emmet \
            compile-extension:git \
            compile-extension:github-authentication \
            compile-extension:html-language-features-server \
            compile-extension:ipynb \
            compile-extension:notebook-renderers \
            compile-extension:json-language-features-server \
            compile-extension:markdown-language-features \
            compile-extension-media \
            compile-extension:microsoft-authentication \
            compile-extension:typescript-language-features \
            compile-extension:vscode-api-tests \
            compile-extension:vscode-colorize-tests \
            compile-extension:vscode-colorize-perf-tests \
            compile-extension:vscode-test-resolver

      - name: 🧪 Run integration tests (Electron)
        if: ${{ inputs.electron_tests }}
        timeout-minutes: 20
        run: ./scripts/test-integration.sh --tfs "Integration Tests"

      - name: 🧪 Run integration tests (Browser, Webkit)
        if: ${{ inputs.browser_tests }}
        timeout-minutes: 20
        run: ./scripts/test-web-integration.sh --browser webkit

      - name: 🧪 Run integration tests (Remote)
        if: ${{ inputs.remote_tests }}
        timeout-minutes: 20
        run: ./scripts/test-remote-integration.sh

      - name: Compile smoke tests
        working-directory: test/smoke
        run: npm run compile

      - name: Compile extensions for smoke tests
        run: npm run gulp compile-extension-media

      - name: Diagnostics before smoke test run
        run: ps -ef
        continue-on-error: true
        if: always()

      - name: 🧪 Run smoke tests (Electron)
        if: ${{ inputs.electron_tests }}
        timeout-minutes: 20
        run: npm run smoketest-no-compile -- --tracing

      - name: 🧪 Run smoke tests (Browser, Chromium)
        if: ${{ inputs.browser_tests }}
        timeout-minutes: 20
        run: npm run smoketest-no-compile -- --web --tracing --headless

      - name: 🧪 Run smoke tests (Remote)
        if: ${{ inputs.remote_tests }}
        timeout-minutes: 20
        run: npm run smoketest-no-compile -- --remote --tracing

      - name: Diagnostics after smoke test run
        run: ps -ef
        continue-on-error: true
        if: always()

      - name: Publish Crash Reports
        uses: actions/upload-artifact@v7
        if: failure()
        continue-on-error: true
        with:
          name: ${{ format('crash-dump-macos-{0}-{1}-{2}', env.VSCODE_ARCH, env.ARTIFACT_NAME, github.run_attempt) }}
          path: .build/crashes
          if-no-files-found: ignore

      # In order to properly symbolify above crash reports
      # (if any), we need the compiled native modules too
      - name: Publish Node Modules
        uses: actions/upload-artifact@v7
        if: failure()
        continue-on-error: true
        with:
          name: ${{ format('node-modules-macos-{0}-{1}-{2}', env.VSCODE_ARCH, env.ARTIFACT_NAME, github.run_attempt) }}
          path: node_modules
          if-no-files-found: ignore

      - name: Publish Log Files
        uses: actions/upload-artifact@v7
        if: always()
        continue-on-error: true
        with:
          name: ${{ format('logs-macos-{0}-{1}-{2}', env.VSCODE_ARCH, env.ARTIFACT_NAME, github.run_attempt) }}
          path: .build/logs
          if-no-files-found: ignore
pr-linux-cli-test .github/workflows/pr-linux-cli-test.yml
Triggers
workflow_call
Runs on
ubuntu-22.04
Jobs
linux-cli-test
Commands
  • set -e curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal --default-toolchain $RUSTUP_TOOLCHAIN echo "$HOME/.cargo/bin" >> $GITHUB_PATH
  • set -e rustup default $RUSTUP_TOOLCHAIN rustup update $RUSTUP_TOOLCHAIN rustup component add clippy
  • set -e rustc --version cargo --version
  • cargo clippy -- -D warnings
  • cargo test
View raw YAML
on:
  workflow_call:
    inputs:
      job_name:
        type: string
        required: true
      rustup_toolchain:
        type: string
        required: true

jobs:
  linux-cli-test:
    name: ${{ inputs.job_name }}
    runs-on: ubuntu-22.04
    env:
      RUSTUP_TOOLCHAIN: ${{ inputs.rustup_toolchain }}
    steps:
      - name: Checkout microsoft/vscode
        uses: actions/checkout@v6

      - name: Install Rust
        run: |
          set -e
          curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal --default-toolchain $RUSTUP_TOOLCHAIN
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH

      - name: Set Rust version
        run: |
          set -e
          rustup default $RUSTUP_TOOLCHAIN
          rustup update $RUSTUP_TOOLCHAIN
          rustup component add clippy

      - name: Check Rust versions
        run: |
          set -e
          rustc --version
          cargo --version

      - name: Clippy lint
        run: cargo clippy -- -D warnings
        working-directory: cli

      - name: 🧪 Run unit tests
        run: cargo test
        working-directory: cli
pr-linux-test .github/workflows/pr-linux-test.yml
Triggers
workflow_call
Runs on
ubuntu-22.04
Jobs
linux-test
Commands
  • set -e # Start X server ./build/azure-pipelines/linux/apt-retry.sh sudo apt-get update ./build/azure-pipelines/linux/apt-retry.sh sudo apt-get install -y pkg-config \ xvfb \ libgtk-3-0 \ libxkbfile-dev \ libkrb5-dev \ libgbm1 \ rpm \ bubblewrap \ socat sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb sudo chmod +x /etc/init.d/xvfb sudo update-rc.d xvfb defaults sudo service xvfb start
  • mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts linux $VSCODE_ARCH $(node -p process.arch) > .build/packagelockhash
  • tar -xzf .build/node_modules_cache/cache.tgz
  • set -e for i in {1..5}; do # try 5 times npm ci && break if [ $i -eq 5 ]; then echo "Npm install failed too many times" >&2 exit 1 fi echo "Npm install failed $i, trying again..." done
  • set -e source ./build/azure-pipelines/linux/setup-env.sh for i in {1..5}; do # try 5 times npm ci && break if [ $i -eq 5 ]; then echo "Npm install failed too many times" >&2 exit 1 fi echo "Npm install failed $i, trying again..." done
  • set -e node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt mkdir -p .build/node_modules_cache tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
  • mkdir -p .build
  • node build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts > .build/builtindepshash
View raw YAML
on:
  workflow_call:
    inputs:
      job_name:
        type: string
        required: true
      electron_tests:
        type: boolean
        default: false
      browser_tests:
        type: boolean
        default: false
      remote_tests:
        type: boolean
        default: false

jobs:
  linux-test:
    name: ${{ inputs.job_name }}
    runs-on: ubuntu-22.04
    env:
      ARTIFACT_NAME: ${{ (inputs.electron_tests && 'electron') || (inputs.browser_tests && 'browser') || (inputs.remote_tests && 'remote') || 'unknown' }}
      NPM_ARCH: x64
      VSCODE_ARCH: x64
    steps:
      - name: Checkout microsoft/vscode
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc

      - name: Setup system services
        run: |
          set -e
          # Start X server
          ./build/azure-pipelines/linux/apt-retry.sh sudo apt-get update
          ./build/azure-pipelines/linux/apt-retry.sh sudo apt-get install -y pkg-config \
            xvfb \
            libgtk-3-0 \
            libxkbfile-dev \
            libkrb5-dev \
            libgbm1 \
            rpm \
            bubblewrap \
            socat
          sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb
          sudo chmod +x /etc/init.d/xvfb
          sudo update-rc.d xvfb defaults
          sudo service xvfb start

      - name: Prepare node_modules cache key
        run: mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts linux $VSCODE_ARCH $(node -p process.arch) > .build/packagelockhash

      - name: Restore node_modules cache
        id: cache-node-modules
        uses: actions/cache/restore@v5
        with:
          path: .build/node_modules_cache
          key: "node_modules-linux-${{ hashFiles('.build/packagelockhash') }}"

      - name: Extract node_modules cache
        if: steps.cache-node-modules.outputs.cache-hit == 'true'
        run: tar -xzf .build/node_modules_cache/cache.tgz

      - name: Install build dependencies
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        working-directory: build
        run: |
          set -e

          for i in {1..5}; do # try 5 times
            npm ci && break
            if [ $i -eq 5 ]; then
              echo "Npm install failed too many times" >&2
              exit 1
            fi
            echo "Npm install failed $i, trying again..."
          done
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Install dependencies
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e

          source ./build/azure-pipelines/linux/setup-env.sh

          for i in {1..5}; do # try 5 times
            npm ci && break
            if [ $i -eq 5 ]; then
              echo "Npm install failed too many times" >&2
              exit 1
            fi
            echo "Npm install failed $i, trying again..."
          done
        env:
          npm_config_arch: ${{ env.NPM_ARCH }}
          VSCODE_ARCH: ${{ env.VSCODE_ARCH }}
          ELECTRON_SKIP_BINARY_DOWNLOAD: 1
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Create node_modules archive
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e
          node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt
          mkdir -p .build/node_modules_cache
          tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt

      - name: Create .build folder
        run: mkdir -p .build

      - name: Prepare built-in extensions cache key
        run: node build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts > .build/builtindepshash

      - name: Restore built-in extensions cache
        id: cache-builtin-extensions
        uses: actions/cache/restore@v5
        with:
          enableCrossOsArchive: true
          path: .build/builtInExtensions
          key: "builtin-extensions-${{ hashFiles('.build/builtindepshash') }}"

      - name: Download built-in extensions
        if: steps.cache-builtin-extensions.outputs.cache-hit != 'true'
        run: node build/lib/builtInExtensions.ts
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Transpile client and extensions
        run: npm run gulp transpile-client-esbuild transpile-extensions

      - name: Download Electron and Playwright
        run: |
          set -e

          for i in {1..3}; do # try 3 times (matching retryCountOnTaskFailure: 3)
            if npm exec -- npm-run-all2 -lp "electron ${{ env.VSCODE_ARCH }}" "playwright-install"; then
              echo "Download successful on attempt $i"
              break
            fi

            if [ $i -eq 3 ]; then
              echo "Download failed after 3 attempts" >&2
              exit 1
            fi

            echo "Download failed on attempt $i, retrying..."
            sleep 5 # optional: add a small delay between retries
          done
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: 🧪 Run unit tests (Electron)
        if: ${{ inputs.electron_tests }}
        timeout-minutes: 15
        run: ./scripts/test.sh --tfs "Unit Tests"
        env:
          DISPLAY: ":10"

      - name: 🧪 Run unit tests (node.js)
        if: ${{ inputs.electron_tests }}
        timeout-minutes: 15
        run: npm run test-node

      - name: 🧪 Run unit tests (Browser, Chromium)
        if: ${{ inputs.browser_tests }}
        timeout-minutes: 30
        run: npm run test-browser-no-install -- --browser chromium --tfs "Browser Unit Tests"
        env:
          DEBUG: "*browser*"

      - name: Build integration tests
        run: |
          set -e
          npm run gulp \
            compile-extension:configuration-editing \
            compile-extension:css-language-features-server \
            compile-extension:emmet \
            compile-extension:git \
            compile-extension:github-authentication \
            compile-extension:html-language-features-server \
            compile-extension:ipynb \
            compile-extension:notebook-renderers \
            compile-extension:json-language-features-server \
            compile-extension:markdown-language-features \
            compile-extension-media \
            compile-extension:microsoft-authentication \
            compile-extension:typescript-language-features \
            compile-extension:vscode-api-tests \
            compile-extension:vscode-colorize-tests \
            compile-extension:vscode-colorize-perf-tests \
            compile-extension:vscode-test-resolver

      - name: 🧪 Run integration tests (Electron)
        if: ${{ inputs.electron_tests }}
        timeout-minutes: 20
        run: ./scripts/test-integration.sh --tfs "Integration Tests"
        env:
          DISPLAY: ":10"

      - name: 🧪 Run integration tests (Browser, Chromium)
        if: ${{ inputs.browser_tests }}
        timeout-minutes: 20
        run: ./scripts/test-web-integration.sh --browser chromium

      - name: 🧪 Run integration tests (Remote)
        if: ${{ inputs.remote_tests }}
        timeout-minutes: 20
        run: ./scripts/test-remote-integration.sh
        env:
          DISPLAY: ":10"

      - name: Compile smoke tests
        working-directory: test/smoke
        run: npm run compile

      - name: Compile extensions for smoke tests
        run: npm run gulp compile-extension-media

      - name: Diagnostics before smoke test run (processes, max_user_watches, number of opened file handles)
        run: |
          set -e
          ps -ef
          cat /proc/sys/fs/inotify/max_user_watches
          lsof | wc -l
        continue-on-error: true
        if: always()

      - name: 🧪 Run smoke tests (Electron)
        if: ${{ inputs.electron_tests }}
        timeout-minutes: 20
        run: npm run smoketest-no-compile -- --tracing
        env:
          DISPLAY: ":10"

      - name: 🧪 Run smoke tests (Browser, Chromium)
        if: ${{ inputs.browser_tests }}
        timeout-minutes: 20
        run: npm run smoketest-no-compile -- --web --tracing --headless

      - name: 🧪 Run smoke tests (Remote)
        if: ${{ inputs.remote_tests }}
        timeout-minutes: 20
        run: npm run smoketest-no-compile -- --remote --tracing
        env:
          DISPLAY: ":10"

      - name: Diagnostics after smoke test run (processes, max_user_watches, number of opened file handles)
        run: |
          set -e
          ps -ef
          cat /proc/sys/fs/inotify/max_user_watches
          lsof | wc -l
        continue-on-error: true
        if: always()

      - name: Publish Crash Reports
        uses: actions/upload-artifact@v7
        if: failure()
        continue-on-error: true
        with:
          name: ${{ format('crash-dump-linux-{0}-{1}-{2}', env.VSCODE_ARCH, env.ARTIFACT_NAME, github.run_attempt) }}
          path: .build/crashes
          if-no-files-found: ignore

      # In order to properly symbolify above crash reports
      # (if any), we need the compiled native modules too
      - name: Publish Node Modules
        uses: actions/upload-artifact@v7
        if: failure()
        continue-on-error: true
        with:
          name: ${{ format('node-modules-linux-{0}-{1}-{2}', env.VSCODE_ARCH, env.ARTIFACT_NAME, github.run_attempt) }}
          path: node_modules
          if-no-files-found: ignore

      - name: Publish Log Files
        uses: actions/upload-artifact@v7
        if: always()
        continue-on-error: true
        with:
          name: ${{ format('logs-linux-{0}-{1}-{2}', env.VSCODE_ARCH, env.ARTIFACT_NAME, github.run_attempt) }}
          path: .build/logs
          if-no-files-found: ignore
pr-node-modules perms .github/workflows/pr-node-modules.yml
Triggers
push
Runs on
ubuntu-22.04, ubuntu-22.04, macos-14-xlarge, self-hosted, 1ES.Pool=1es-vscode-oss-windows-2022-x64
Jobs
compile, linux, macOS, windows
Commands
  • mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts compile $(node -p process.arch) > .build/packagelockhash
  • tar -xzf .build/node_modules_cache/cache.tgz
  • sudo apt update -y && sudo apt install -y build-essential pkg-config libx11-dev libx11-xcb-dev libxkbfile-dev libnotify-bin libkrb5-dev
  • set -e for i in {1..5}; do # try 5 times npm ci && break if [ $i -eq 5 ]; then echo "Npm install failed too many times" >&2 exit 1 fi echo "Npm install failed $i, trying again..." done
  • set -e node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt mkdir -p .build/node_modules_cache tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt
  • set -e mkdir -p .build node build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts > .build/builtindepshash
  • node build/lib/builtInExtensions.ts
  • mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts linux $VSCODE_ARCH $(node -p process.arch) > .build/packagelockhash
View raw YAML
name: Code OSS (node_modules)

on:
  push:
    branches:
      - main

permissions: {}

jobs:
  compile:
    name: Compile
    runs-on: ubuntu-22.04
    steps:
      - name: Checkout microsoft/vscode
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc

      - name: Prepare node_modules cache key
        run: mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts compile $(node -p process.arch) > .build/packagelockhash

      - name: Restore node_modules cache
        id: cache-node-modules
        uses: actions/cache@v5
        with:
          path: .build/node_modules_cache
          key: "node_modules-compile-${{ hashFiles('.build/packagelockhash') }}"

      - name: Extract node_modules cache
        if: steps.cache-node-modules.outputs.cache-hit == 'true'
        run: tar -xzf .build/node_modules_cache/cache.tgz

      - name: Install build tools
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: sudo apt update -y && sudo apt install -y build-essential pkg-config libx11-dev libx11-xcb-dev libxkbfile-dev libnotify-bin libkrb5-dev

      - name: Install dependencies
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e

          for i in {1..5}; do # try 5 times
            npm ci && break
            if [ $i -eq 5 ]; then
              echo "Npm install failed too many times" >&2
              exit 1
            fi
            echo "Npm install failed $i, trying again..."
          done
        env:
          ELECTRON_SKIP_BINARY_DOWNLOAD: 1
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
          GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}

      - name: Create node_modules archive
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e
          node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt
          mkdir -p .build/node_modules_cache
          tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt

      - name: Prepare built-in extensions cache key
        run: |
          set -e
          mkdir -p .build
          node build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts > .build/builtindepshash

      - name: Restore built-in extensions cache
        id: cache-builtin-extensions
        uses: actions/cache@v5
        with:
          enableCrossOsArchive: true
          path: .build/builtInExtensions
          key: "builtin-extensions-${{ hashFiles('.build/builtindepshash') }}"

      - name: Download built-in extensions
        if: steps.cache-builtin-extensions.outputs.cache-hit != 'true'
        run: node build/lib/builtInExtensions.ts
        env:
          GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}

  linux:
    name: Linux
    runs-on: ubuntu-22.04
    env:
      NPM_ARCH: x64
      VSCODE_ARCH: x64
    steps:
      - name: Checkout microsoft/vscode
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc

      - name: Prepare node_modules cache key
        run: mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts linux $VSCODE_ARCH $(node -p process.arch) > .build/packagelockhash

      - name: Restore node_modules cache
        id: cache-node-modules
        uses: actions/cache@v5
        with:
          path: .build/node_modules_cache
          key: "node_modules-linux-${{ hashFiles('.build/packagelockhash') }}"

      - name: Install build dependencies
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        working-directory: build
        run: |
          set -e

          for i in {1..5}; do # try 5 times
            npm ci && break
            if [ $i -eq 5 ]; then
              echo "Npm install failed too many times" >&2
              exit 1
            fi
            echo "Npm install failed $i, trying again..."
          done
        env:
          GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}

      - name: Install dependencies
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e

          source ./build/azure-pipelines/linux/setup-env.sh

          for i in {1..5}; do # try 5 times
            npm ci && break
            if [ $i -eq 5 ]; then
              echo "Npm install failed too many times" >&2
              exit 1
            fi
            echo "Npm install failed $i, trying again..."
          done
        env:
          npm_config_arch: ${{ env.NPM_ARCH }}
          VSCODE_ARCH: ${{ env.VSCODE_ARCH }}
          ELECTRON_SKIP_BINARY_DOWNLOAD: 1
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
          GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}

      - name: Create node_modules archive
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e
          node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt
          mkdir -p .build/node_modules_cache
          tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt

  macOS:
    name: macOS
    runs-on: macos-14-xlarge
    env:
      NPM_ARCH: arm64
      VSCODE_ARCH: arm64
    steps:
      - name: Checkout microsoft/vscode
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc

      - name: Prepare node_modules cache key
        run: mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts darwin $VSCODE_ARCH $(node -p process.arch) > .build/packagelockhash

      - name: Restore node_modules cache
        id: cache-node-modules
        uses: actions/cache@v5
        with:
          path: .build/node_modules_cache
          key: "node_modules-macos-${{ hashFiles('.build/packagelockhash') }}"

      - name: Install dependencies
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e
          c++ --version
          xcode-select -print-path
          python3 -m pip install --break-system-packages setuptools

          for i in {1..5}; do # try 5 times
            npm ci && break
            if [ $i -eq 5 ]; then
              echo "Npm install failed too many times" >&2
              exit 1
            fi
            echo "Npm install failed $i, trying again..."
          done
        env:
          npm_config_arch: ${{ env.NPM_ARCH }}
          VSCODE_ARCH: ${{ env.VSCODE_ARCH }}
          ELECTRON_SKIP_BINARY_DOWNLOAD: 1
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
          GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}
          # Avoid using dlopen to load Kerberos on macOS which can cause missing libraries
          # https://github.com/mongodb-js/kerberos/commit/04044d2814ad1d01e77f1ce87f26b03d86692cf2
          # flipped the default to support legacy linux distros which shouldn't happen
          # on macOS.
          GYP_DEFINES: "kerberos_use_rtld=false"

      - name: Create node_modules archive
        if: steps.cache-node-modules.outputs.cache-hit != 'true'
        run: |
          set -e
          node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt
          mkdir -p .build/node_modules_cache
          tar -czf .build/node_modules_cache/cache.tgz --files-from .build/node_modules_list.txt

  windows:
    name: Windows
    runs-on: [ self-hosted, 1ES.Pool=1es-vscode-oss-windows-2022-x64 ]
    env:
      NPM_ARCH: x64
      VSCODE_ARCH: x64
    steps:
      - name: Checkout microsoft/vscode
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc

      - name: Prepare node_modules cache key
        shell: pwsh
        run: |
          mkdir .build -ea 0
          node build/azure-pipelines/common/computeNodeModulesCacheKey.ts win32 ${{ env.VSCODE_ARCH }} $(node -p process.arch) > .build/packagelockhash

      - name: Restore node_modules cache
        uses: actions/cache@v5
        id: node-modules-cache
        with:
          path: .build/node_modules_cache
          key: "node_modules-windows-${{ hashFiles('.build/packagelockhash') }}"

      - name: Install dependencies
        if: steps.node-modules-cache.outputs.cache-hit != 'true'
        shell: pwsh
        run: |
          . build/azure-pipelines/win32/exec.ps1
          $ErrorActionPreference = "Stop"

          for ($i = 1; $i -le 5; $i++) {
            try {
              exec { npm ci }
              break
            }
            catch {
              if ($i -eq 5) {
                Write-Error "npm ci failed after 5 attempts"
                throw
              }
              Write-Host "npm ci failed attempt $i, retrying..."
              Start-Sleep -Seconds 2
            }
          }
        env:
          npm_config_arch: ${{ env.NPM_ARCH }}
          npm_config_foreground_scripts: "true"
          VSCODE_ARCH: ${{ env.VSCODE_ARCH }}
          ELECTRON_SKIP_BINARY_DOWNLOAD: 1
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
          GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}

      - name: Create node_modules archive
        if: steps.node-modules-cache.outputs.cache-hit != 'true'
        shell: pwsh
        run: |
          . build/azure-pipelines/win32/exec.ps1
          $ErrorActionPreference = "Stop"
          exec { node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt }
          exec { mkdir -Force .build/node_modules_cache }
          exec { 7z.exe a .build/node_modules_cache/cache.7z -mx3 `@.build/node_modules_list.txt }
pr-win32-test .github/workflows/pr-win32-test.yml
Triggers
workflow_call
Runs on
windows-2022
Jobs
windows-test
Commands
  • mkdir .build -ea 0 node build/azure-pipelines/common/computeNodeModulesCacheKey.ts win32 ${{ env.VSCODE_ARCH }} $(node -p process.arch) > .build/packagelockhash
  • 7z.exe x .build/node_modules_cache/cache.7z -aoa
  • . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" for ($i = 1; $i -le 5; $i++) { try { exec { npm ci } break } catch { if ($i -eq 5) { Write-Error "npm ci failed after 5 attempts" throw } Write-Host "npm ci failed attempt $i, retrying..." Start-Sleep -Seconds 2 } }
  • . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" exec { node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt } exec { mkdir -Force .build/node_modules_cache } exec { 7z.exe a .build/node_modules_cache/cache.7z -mx3 `@.build/node_modules_list.txt }
  • mkdir .build -ea 0
  • node build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts > .build/builtindepshash
  • node build/lib/builtInExtensions.ts
  • npm run gulp "transpile-client-esbuild" "transpile-extensions"
View raw YAML
on:
  workflow_call:
    inputs:
      job_name:
        type: string
        required: true
      electron_tests:
        type: boolean
        default: false
      browser_tests:
        type: boolean
        default: false
      remote_tests:
        type: boolean
        default: false

jobs:
  windows-test:
    name: ${{ inputs.job_name }}
    runs-on: windows-2022
    env:
      ARTIFACT_NAME: ${{ (inputs.electron_tests && 'electron') || (inputs.browser_tests && 'browser') || (inputs.remote_tests && 'remote') || 'unknown' }}
      NPM_ARCH: x64
      VSCODE_ARCH: x64
    steps:
      - name: Checkout microsoft/vscode
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc

      - name: Prepare node_modules cache key
        shell: pwsh
        run: |
          mkdir .build -ea 0
          node build/azure-pipelines/common/computeNodeModulesCacheKey.ts win32 ${{ env.VSCODE_ARCH }} $(node -p process.arch) > .build/packagelockhash

      - name: Restore node_modules cache
        uses: actions/cache/restore@v5
        id: node-modules-cache
        with:
          path: .build/node_modules_cache
          key: "node_modules-windows-${{ hashFiles('.build/packagelockhash') }}"

      - name: Extract node_modules cache
        if: steps.node-modules-cache.outputs.cache-hit == 'true'
        shell: pwsh
        run: 7z.exe x .build/node_modules_cache/cache.7z -aoa

      - name: Install dependencies
        if: steps.node-modules-cache.outputs.cache-hit != 'true'
        shell: pwsh
        run: |
          . build/azure-pipelines/win32/exec.ps1
          $ErrorActionPreference = "Stop"

          for ($i = 1; $i -le 5; $i++) {
            try {
              exec { npm ci }
              break
            }
            catch {
              if ($i -eq 5) {
                Write-Error "npm ci failed after 5 attempts"
                throw
              }
              Write-Host "npm ci failed attempt $i, retrying..."
              Start-Sleep -Seconds 2
            }
          }
        env:
          npm_config_arch: ${{ env.NPM_ARCH }}
          npm_config_foreground_scripts: "true"
          VSCODE_ARCH: ${{ env.VSCODE_ARCH }}
          ELECTRON_SKIP_BINARY_DOWNLOAD: 1
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Create node_modules archive
        if: steps.node-modules-cache.outputs.cache-hit != 'true'
        shell: pwsh
        run: |
          . build/azure-pipelines/win32/exec.ps1
          $ErrorActionPreference = "Stop"
          exec { node build/azure-pipelines/common/listNodeModules.ts .build/node_modules_list.txt }
          exec { mkdir -Force .build/node_modules_cache }
          exec { 7z.exe a .build/node_modules_cache/cache.7z -mx3 `@.build/node_modules_list.txt }

      - name: Create .build folder
        shell: pwsh
        run: mkdir .build -ea 0

      - name: Prepare built-in extensions cache key
        shell: pwsh
        run: node build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts > .build/builtindepshash

      - name: Restore built-in extensions cache
        id: cache-builtin-extensions
        uses: actions/cache/restore@v5
        with:
          enableCrossOsArchive: true
          path: .build/builtInExtensions
          key: "builtin-extensions-${{ hashFiles('.build/builtindepshash') }}"

      - name: Download built-in extensions
        if: steps.cache-builtin-extensions.outputs.cache-hit != 'true'
        run: node build/lib/builtInExtensions.ts
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Transpile client and extensions
        shell: pwsh
        run: npm run gulp "transpile-client-esbuild" "transpile-extensions"

      - name: Download Electron and Playwright
        shell: pwsh
        run: |
          for ($i = 1; $i -le 3; $i++) {
            try {
              npm exec -- npm-run-all2 -lp "electron ${{ env.VSCODE_ARCH }}" "playwright-install"
              break
            }
            catch {
              if ($i -eq 3) {
                Write-Error "Download failed after 3 attempts"
                throw
              }
              Write-Host "Download failed attempt $i, retrying..."
              Start-Sleep -Seconds 2
            }
          }
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: 🧪 Run unit tests (Electron)
        if: ${{ inputs.electron_tests }}
        shell: pwsh
        run: .\scripts\test.bat --tfs "Unit Tests"
        timeout-minutes: 15

      - name: 🧪 Run unit tests (node.js)
        if: ${{ inputs.electron_tests }}
        shell: pwsh
        run: npm run test-node
        timeout-minutes: 15

      - name: 🧪 Run unit tests (Browser, Chromium)
        if: ${{ inputs.browser_tests }}
        shell: pwsh
        run: node test/unit/browser/index.js --browser chromium --tfs "Browser Unit Tests"
        env:
          DEBUG: "*browser*"
        timeout-minutes: 20

      - name: Build integration tests
        shell: pwsh
        run: |
          . build/azure-pipelines/win32/exec.ps1
          $ErrorActionPreference = "Stop"
          exec { npm run gulp `
            compile-extension:configuration-editing `
            compile-extension:css-language-features-server `
            compile-extension:emmet `
            compile-extension:git `
            compile-extension:github-authentication `
            compile-extension:html-language-features-server `
            compile-extension:ipynb `
            compile-extension:notebook-renderers `
            compile-extension:json-language-features-server `
            compile-extension:markdown-language-features `
            compile-extension-media `
            compile-extension:microsoft-authentication `
            compile-extension:typescript-language-features `
            compile-extension:vscode-api-tests `
            compile-extension:vscode-colorize-tests `
            compile-extension:vscode-colorize-perf-tests `
            compile-extension:vscode-test-resolver `
          }

      - name: Diagnostics before integration test runs
        shell: pwsh
        run: .\build\azure-pipelines\win32\listprocesses.bat
        continue-on-error: true
        if: always()

      - name: 🧪 Run integration tests (Electron)
        if: ${{ inputs.electron_tests }}
        shell: pwsh
        run: .\scripts\test-integration.bat --tfs "Integration Tests"
        timeout-minutes: 20

      - name: 🧪 Run integration tests (Browser, Chromium)
        if: ${{ inputs.browser_tests }}
        shell: pwsh
        run: .\scripts\test-web-integration.bat --browser chromium
        timeout-minutes: 20

      - name: 🧪 Run integration tests (Remote)
        if: ${{ inputs.remote_tests }}
        shell: pwsh
        run: .\scripts\test-remote-integration.bat
        timeout-minutes: 20

      - name: Diagnostics after integration test runs
        shell: pwsh
        run: .\build\azure-pipelines\win32\listprocesses.bat
        continue-on-error: true
        if: always()

      - name: Diagnostics before smoke test run
        shell: pwsh
        run: .\build\azure-pipelines\win32\listprocesses.bat
        continue-on-error: true
        if: always()

      - name: Compile smoke tests
        working-directory: test/smoke
        shell: pwsh
        run: npm run compile

      - name: Compile extensions for smoke tests
        shell: pwsh
        run: npm run gulp compile-extension-media

      - name: 🧪 Run smoke tests (Electron)
        if: ${{ inputs.electron_tests }}
        timeout-minutes: 20
        shell: pwsh
        run: npm run smoketest-no-compile -- --tracing

      - name: 🧪 Run smoke tests (Browser, Chromium)
        if: ${{ inputs.browser_tests }}
        timeout-minutes: 20
        shell: pwsh
        run: npm run smoketest-no-compile -- --web --tracing --headless

      - name: 🧪 Run smoke tests (Remote)
        if: ${{ inputs.remote_tests }}
        timeout-minutes: 20
        shell: pwsh
        run: npm run smoketest-no-compile -- --remote --tracing

      - name: Diagnostics after smoke test run
        shell: pwsh
        run: .\build\azure-pipelines\win32\listprocesses.bat
        continue-on-error: true
        if: always()

      - name: Publish Crash Reports
        uses: actions/upload-artifact@v7
        if: failure()
        continue-on-error: true
        with:
          name: ${{ format('crash-dump-windows-{0}-{1}-{2}', env.VSCODE_ARCH, env.ARTIFACT_NAME, github.run_attempt) }}
          path: .build/crashes
          if-no-files-found: ignore

      # In order to properly symbolify above crash reports
      # (if any), we need the compiled native modules too
      - name: Publish Node Modules
        uses: actions/upload-artifact@v7
        if: failure()
        continue-on-error: true
        with:
          name: ${{ format('node-modules-windows-{0}-{1}-{2}', env.VSCODE_ARCH, env.ARTIFACT_NAME, github.run_attempt) }}
          path: node_modules
          if-no-files-found: ignore

      - name: Publish Log Files
        uses: actions/upload-artifact@v7
        if: always()
        continue-on-error: true
        with:
          name: ${{ format('logs-windows-{0}-{1}-{2}', env.VSCODE_ARCH, env.ARTIFACT_NAME, github.run_attempt) }}
          path: .build/logs
          if-no-files-found: ignore
screenshot-test perms .github/workflows/screenshot-test.yml
Triggers
push, pull_request
Runs on
ubuntu-latest
Jobs
screenshots
Commands
  • npm ci --ignore-scripts
  • npm ci
  • rm -f package-lock.json && npm install
  • npm run build
  • npx playwright install chromium
  • ./node_modules/.bin/component-explorer screenshot --project ./test/componentFixtures/component-explorer.json
  • ./node_modules/.bin/component-explorer screenshot:compare \ --project ./test/componentFixtures \ --report ./test/componentFixtures/.screenshots/report
  • mkdir -p /tmp/explorer-artifact/screenshot-report cp -r build/vite/dist/* /tmp/explorer-artifact/ if [ -d test/componentFixtures/.screenshots/report ]; then cp -r test/componentFixtures/.screenshots/report/* /tmp/explorer-artifact/screenshot-report/ fi
View raw YAML
name: Checking Component Screenshots

on:
  push:
    branches: [main]
  pull_request:
    branches:
      - main
      - 'release/*'

permissions:
  contents: read
  statuses: write

concurrency:
  group: screenshots-${{ github.event.pull_request.number || github.sha }}
  cancel-in-progress: true

jobs:
  screenshots:
    name: Checking Component Screenshots
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          lfs: true

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc

      - name: Install dependencies
        run: npm ci --ignore-scripts
        env:
          ELECTRON_SKIP_BINARY_DOWNLOAD: 1
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Install build dependencies
        run: npm ci
        working-directory: build

      - name: Install build/vite dependencies
        run: rm -f package-lock.json && npm install
        working-directory: build/vite

      - name: Build vite
        run: npm run build
        working-directory: build/vite

      - name: Install Playwright Chromium
        run: npx playwright install chromium

      - name: Capture screenshots
        run: ./node_modules/.bin/component-explorer screenshot --project ./test/componentFixtures/component-explorer.json

      - name: Compare screenshots
        id: compare
        run: |
          ./node_modules/.bin/component-explorer screenshot:compare \
            --project ./test/componentFixtures \
            --report ./test/componentFixtures/.screenshots/report
        continue-on-error: true

      - name: Prepare explorer artifact
        run: |
          mkdir -p /tmp/explorer-artifact/screenshot-report
          cp -r build/vite/dist/* /tmp/explorer-artifact/
          if [ -d test/componentFixtures/.screenshots/report ]; then
            cp -r test/componentFixtures/.screenshots/report/* /tmp/explorer-artifact/screenshot-report/
          fi

      - name: Upload explorer artifact
        uses: actions/upload-artifact@v7
        with:
          name: component-explorer
          path: /tmp/explorer-artifact/

      - name: Upload screenshot report
        if: steps.compare.outcome == 'failure'
        uses: actions/upload-artifact@v7
        with:
          name: screenshot-diff
          path: |
            test/componentFixtures/.screenshots/current/
            test/componentFixtures/.screenshots/report/

      - name: Set check title
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          REPORT="test/componentFixtures/.screenshots/report/report.json"
          STATE="success"
          if [ -f "$REPORT" ]; then
            CHANGED=$(node -e "const r = require('./$REPORT'); console.log(r.summary.added + r.summary.removed + r.summary.changed)")
            TITLE="⚠ ${CHANGED} screenshots changed"
            BLOCKS_CI=$(node -e "
              const r = require('./$REPORT');
              const blocking = Object.entries(r.fixtures).filter(([, f]) =>
                f.status !== 'unchanged' && (f.labels || []).includes('blocks-ci')
              );
              if (blocking.length > 0) {
                console.log(blocking.map(([name]) => name).join(', '));
              }
            ")
            if [ -n "$BLOCKS_CI" ]; then
              STATE="failure"
              TITLE="❌ ${CHANGED} screenshots changed (blocks CI: ${BLOCKS_CI})"
            fi
          else
            TITLE="✅ Screenshots match"
          fi

          SHA="${{ github.event.pull_request.head.sha || github.sha }}"
          DETAILS_URL="https://hediet-ghartifactpreview.azurewebsites.net/${{ github.repository }}/run/${{ github.run_id }}/component-explorer/___explorer.html?report=./screenshot-report/report.json&search=changed"

          gh api "repos/${{ github.repository }}/statuses/$SHA" \
            --input - <<EOF || echo "::warning::Could not create commit status (expected for fork PRs)"
          {"state":"$STATE","target_url":"$DETAILS_URL","description":"$TITLE","context":"Component Screenshots"}
          EOF

      # - name: Post PR comment
      #   if: github.event_name == 'pull_request'
      #   env:
      #     GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      #   run: |
      #     COMMENT_MARKER="<!-- screenshot-report -->"
      #     BODY="$COMMENT_MARKER"$'\n'
      #
      #     if [ -f test/componentFixtures/.screenshots/report.md ]; then
      #       BODY+=$(cat test/componentFixtures/.screenshots/report.md)
      #       BODY+=$'\n\n'
      #       BODY+="📦 [Download the \`screenshot-diff\` artifact](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) to review images."
      #     else
      #       BODY+="## Screenshots ✅"$'\n\n'
      #       BODY+="No visual changes detected."
      #     fi
      #
      #     # Find existing comment
      #     EXISTING=$(gh api "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \
      #       --paginate --jq ".[] | select(.body | startswith(\"$COMMENT_MARKER\")) | .id" | head -1)
      #
      #     if [ -n "$EXISTING" ]; then
      #       gh api "repos/${{ github.repository }}/issues/comments/$EXISTING" -X PATCH -f body="$BODY"
      #     else
      #       gh pr comment "${{ github.event.pull_request.number }}" --body "$BODY"
      #     fi
sessions-e2e perms .github/workflows/sessions-e2e.yml
Triggers
Runs on
ubuntu-latest
Jobs
sessions-e2e
Commands
  • sudo apt update -y && sudo apt install -y build-essential pkg-config libx11-dev libx11-xcb-dev libxkbfile-dev libnotify-bin libkrb5-dev xvfb
  • npm ci
  • npm ci
  • npm run transpile-client
  • npm ci
  • npx playwright install chromium
  • xvfb-run npm test
View raw YAML
name: Sessions E2E Tests

# on:
#   pull_request:
#     branches:
#       - main
#       - 'release/*'
#     paths:
#       - 'src/vs/sessions/**'
#       - 'scripts/code-sessions-web.*'

permissions:
  contents: read

concurrency:
  group: sessions-e2e-${{ github.event.pull_request.number || github.sha }}
  cancel-in-progress: true

jobs:
  sessions-e2e:
    name: Sessions E2E Tests
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc

      - name: Install build tools
        run: sudo apt update -y && sudo apt install -y build-essential pkg-config libx11-dev libx11-xcb-dev libxkbfile-dev libnotify-bin libkrb5-dev xvfb

      - name: Install dependencies
        run: npm ci
        env:
          ELECTRON_SKIP_BINARY_DOWNLOAD: 1
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Install build dependencies
        run: npm ci
        working-directory: build

      - name: Transpile sources
        run: npm run transpile-client

      - name: Install E2E test dependencies
        run: npm ci
        working-directory: src/vs/sessions/test/e2e

      - name: Install Playwright browsers
        run: npx playwright install chromium

      - name: Run Sessions E2E tests
        run: xvfb-run npm test
        working-directory: src/vs/sessions/test/e2e

      - name: Upload failure screenshots
        if: failure()
        uses: actions/upload-artifact@v7
        with:
          name: sessions-e2e-failures
          path: src/vs/sessions/test/e2e/out/failure-*.png
          retention-days: 7
telemetry perms .github/workflows/telemetry.yml
Triggers
pull_request
Runs on
ubuntu-latest
Jobs
check-metadata
Commands
  • npx --package=@vscode/telemetry-extractor@1.14.0 --yes vscode-telemetry-extractor -s .
View raw YAML
name: 'Telemetry'
on: pull_request
permissions: {}
jobs:
  check-metadata:
    name: 'Check metadata'
    runs-on: 'ubuntu-latest'

    steps:
      - uses: 'actions/checkout@v6'
        with:
          persist-credentials: false

      - uses: 'actions/setup-node@v6'
        with:
          node-version: 'lts/*'

      - name: 'Run vscode-telemetry-extractor'
        run: 'npx --package=@vscode/telemetry-extractor@1.14.0 --yes vscode-telemetry-extractor -s .'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}