vitejs/vite

12 workflows · maturity 67% · 7 patterns · GitHub ↗

Security 21.25/100

Practices

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

Detected patterns

Security dimensions

permissions
6.3
security scan
0
supply chain
0
secret handling
15
harden runner
0

Workflows (12)

ci matrix perms .github/workflows/ci.yml
Triggers
push, pull_request, workflow_dispatch
Runs on
ubuntu-slim, ${{ matrix.os }}, ubuntu-slim, ubuntu-slim, ubuntu-latest
Jobs
changed, test, test-passed, test-failed, lint
Matrix
include, include.node_version, include.os, node_version, os→ 20, 22, 24, macos-latest, ubuntu-latest, windows-latest
Actions
tj-actions/changed-files, pnpm/action-setup, pnpm/action-setup
Commands
  • pnpm install
  • echo "PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/playwright-bin" >> $GITHUB_ENV PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')" echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV
  • echo "PLAYWRIGHT_BROWSERS_PATH=$HOME\.cache\playwright-bin" >> $env:GITHUB_ENV $env:PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')" echo "PLAYWRIGHT_VERSION=$env:PLAYWRIGHT_VERSION" >> $env:GITHUB_ENV
  • pnpm playwright install chromium
  • pnpm run build
  • pnpm run test-unit
  • pnpm run test-serve
  • pnpm run test-build
View raw YAML
name: CI

env:
  # 7 GiB by default on GitHub, setting to 6 GiB
  # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
  NODE_OPTIONS: --max-old-space-size=6144
  # install playwright binary manually (because pnpm only runs install script once)
  PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
  # Vitest auto retry on flaky segfault
  VITEST_SEGFAULT_RETRY: 3

# Remove default permissions of GITHUB_TOKEN for security
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
permissions: {}

on:
  push:
    branches:
      - main
      - release/*
      - feat/*
      - fix/*
      - perf/*
      - "v[0-9]+" # v1, v2, ...
      - "v[0-9]+.[0-9]+" # v4.0, v4.1, ...
  pull_request:
  workflow_dispatch:

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

jobs:
  changed:
    name: Get changed files
    runs-on: ubuntu-slim
    outputs:
      should_skip: ${{ steps.changed-files.outputs.only_changed == 'true' }}

    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          # Assume PRs are less than 50 commits
          fetch-depth: 50

      - name: Get changed files
        id: changed-files
        uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5
        with:
          files: |
            docs/**
            .github/**
            !.github/workflows/ci.yml
            packages/create-vite/template**
            **.md

  test:
    needs: changed
    if: needs.changed.outputs.should_skip != 'true'
    timeout-minutes: 20
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest]
        node_version: [20, 22, 24]
        include:
          # Active LTS + other OS
          - os: macos-latest
            node_version: 24
          - os: windows-latest
            node_version: 24
      fail-fast: false

    name: "Build&Test: node-${{ matrix.node_version }}, ${{ matrix.os }}"
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Install pnpm
        uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0

      - name: Set node version to ${{ matrix.node_version }}
        uses: actions/setup-node@v6
        with:
          node-version: ${{ matrix.node_version }}
          cache: "pnpm"

      - name: Install deps
        run: pnpm install

      # Install playwright's binary under custom directory to cache
      - name: (non-windows) Set Playwright path and Get playwright version
        if: runner.os != 'Windows'
        run: |
          echo "PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/playwright-bin" >> $GITHUB_ENV
          PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')"
          echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV
      - name: (windows) Set Playwright path and Get playwright version
        if: runner.os == 'Windows'
        run: |
          echo "PLAYWRIGHT_BROWSERS_PATH=$HOME\.cache\playwright-bin" >> $env:GITHUB_ENV
          $env:PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')"
          echo "PLAYWRIGHT_VERSION=$env:PLAYWRIGHT_VERSION" >> $env:GITHUB_ENV

      - name: Cache Playwright's binary
        uses: actions/cache@v5
        with:
          key: ${{ runner.os }}-playwright-bin-v1-${{ env.PLAYWRIGHT_VERSION }}
          path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }}
          restore-keys: |
            ${{ runner.os }}-playwright-bin-v1-

      - name: Install Playwright
        # does not need to explicitly set chromium after https://github.com/microsoft/playwright/issues/14862 is solved
        run: pnpm playwright install chromium

      - name: Build
        run: pnpm run build

      - name: Test unit
        run: pnpm run test-unit

      - name: Test serve
        run: pnpm run test-serve

      - name: Test build
        run: pnpm run test-build

  test-passed:
    if: (!cancelled() && !failure())
    needs: test
    runs-on: ubuntu-slim
    name: Build & Test Passed or Skipped
    steps:
      - run: echo "Build & Test Passed or Skipped"

  test-failed:
    if: (!cancelled() && failure())
    needs: test
    runs-on: ubuntu-slim
    name: Build & Test Failed
    steps:
      - run: echo "Build & Test Failed"

  lint:
    timeout-minutes: 10
    runs-on: ubuntu-latest
    name: "Lint: node-24, ubuntu-latest"
    steps:
      - uses: actions/checkout@v6

      - name: Install pnpm
        uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0

      - name: Set node version to 24
        uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: "pnpm"

      - name: Install deps
        run: pnpm install

      - name: Build
        run: pnpm run build

      - name: Lint
        run: pnpm run lint

      - name: Check formatting
        run: pnpm prettier --write --log-level=warn . && git diff --exit-code

      - name: Typecheck
        run: pnpm run typecheck

      - name: Test docs
        run: pnpm run test-docs

      # From https://github.com/rhysd/actionlint/blob/main/docs/usage.md#use-actionlint-on-github-actions
      - name: Check workflow files
        run: |
          bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
          ./actionlint -color -shellcheck=""
copilot-setup-steps .github/workflows/copilot-setup-steps.yml
Triggers
workflow_dispatch, push, pull_request
Runs on
ubuntu-latest
Jobs
copilot-setup-steps
Actions
pnpm/action-setup
Commands
  • pnpm install
  • echo "PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/playwright-bin" >> $GITHUB_ENV PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')" echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV
  • echo "PLAYWRIGHT_BROWSERS_PATH=$HOME\.cache\playwright-bin" >> $env:GITHUB_ENV $env:PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')" echo "PLAYWRIGHT_VERSION=$env:PLAYWRIGHT_VERSION" >> $env:GITHUB_ENV
  • pnpm playwright install chromium
View raw YAML
on:
  workflow_dispatch:
  push:
    paths:
      - .github/workflows/copilot-setup-steps.yml
  pull_request:
    paths:
      - .github/workflows/copilot-setup-steps.yml

jobs:
  copilot-setup-steps:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Install pnpm
        uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0

      - name: Set node version to 24
        uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: "pnpm"

      - name: Install deps
        run: pnpm install

      # Install playwright's binary under custom directory to cache
      - name: (non-windows) Set Playwright path and Get playwright version
        if: runner.os != 'Windows'
        run: |
          echo "PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/playwright-bin" >> $GITHUB_ENV
          PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')"
          echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV
      - name: (windows) Set Playwright path and Get playwright version
        if: runner.os == 'Windows'
        run: |
          echo "PLAYWRIGHT_BROWSERS_PATH=$HOME\.cache\playwright-bin" >> $env:GITHUB_ENV
          $env:PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')"
          echo "PLAYWRIGHT_VERSION=$env:PLAYWRIGHT_VERSION" >> $env:GITHUB_ENV

      - name: Install Playwright
        # does not need to explicitly set chromium after https://github.com/microsoft/playwright/issues/14862 is solved
        run: pnpm playwright install chromium
ecosystem-ci-trigger .github/workflows/ecosystem-ci-trigger.yml
Triggers
issue_comment
Runs on
ubuntu-slim
Jobs
trigger
Actions
actions/create-github-app-token
View raw YAML
name: ecosystem-ci trigger

on:
  issue_comment:
    types: [created]

jobs:
  trigger:
    runs-on: ubuntu-slim
    if: github.repository == 'vitejs/vite' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/ecosystem-ci run')
    permissions:
      issues: write # to add / delete reactions, post comments
      pull-requests: write # to read PR data, and to add labels
      actions: read # to check workflow status
    steps:
      - name: Check User Permissions
        uses: actions/github-script@v8
        id: check-permissions
        with:
          script: |
            const user = context.payload.sender.login
            console.log(`Validate user: ${user}`)

            const additionalAllowedUsers = ['lukastaegert']

            let hasTriagePermission = false
            try {
              const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
                owner: context.repo.owner,
                repo: context.repo.repo,
                username: user,
              });
              hasTriagePermission = data.user.permissions.triage
            } catch (e) {
              console.warn(e)
            }

            if (hasTriagePermission || additionalAllowedUsers.includes(user)) {
              console.log('User is allowed. Adding +1 reaction.')
              await github.rest.reactions.createForIssueComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: context.payload.comment.id,
                content: '+1',
              })
            } else {
              console.log('User is not allowed. Adding -1 reaction.')
              await github.rest.reactions.createForIssueComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: context.payload.comment.id,
                content: '-1',
              })
              throw new Error('User does not have the necessary permissions.')
            }

      - name: Get PR Data
        uses: actions/github-script@v8
        id: get-pr-data
        with:
          script: |
            console.log(`Get PR info: ${context.repo.owner}/${context.repo.repo}#${context.issue.number}`)
            const { data: pr } = await github.rest.pulls.get({
              owner: context.repo.owner,
              repo: context.repo.repo,
              pull_number: context.issue.number
            })

            const commentCreatedAt = new Date(context.payload.comment.created_at)
            const commitPushedAt = new Date(pr.head.repo.pushed_at)

            console.log(`Comment created at: ${commentCreatedAt.toISOString()}`)
            console.log(`PR last pushed at: ${commitPushedAt.toISOString()}`)

            // Check if any commits were pushed after the comment was created
            if (commitPushedAt > commentCreatedAt) {
              const errorMsg = [
                '⚠️ Security warning: PR was updated after the trigger command was posted.',
                '',
                `Comment posted at: ${commentCreatedAt.toISOString()}`,
                `PR last pushed at: ${commitPushedAt.toISOString()}`,
                '',
                'This could indicate an attempt to inject code after approval.',
                'Please review the latest changes and re-run /ecosystem-ci run if they are acceptable.'
              ].join('\n')

              core.setFailed(errorMsg)

              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                body: errorMsg
              })

              throw new Error('PR was pushed to after comment was created')
            }

            core.setOutput('head_sha', pr.head.sha)
            return {
              num: context.issue.number,
              branchName: pr.head.ref,
              commit: pr.head.sha,
              repo: pr.head.repo.full_name
            }

      - name: Check Package Existence
        uses: actions/github-script@v8
        id: check-package
        with:
          script: |
            const prData = ${{ steps.get-pr-data.outputs.result }}
            const url = `https://pkg.pr.new/vite@${prData.commit}`
            const response = await fetch(url)
            console.log(`Package check URL: ${url}, Status: ${response.status}`)

            // Add 'rocket' reaction to the issue comment
            if (response.status === 404) {
              const { data: reaction } = await github.rest.reactions.createForIssueComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: context.payload.comment.id,
                content: 'rocket',
              })
              return { exists: false, reaction: reaction.id }
            }

            return { exists: true, reaction: null }

      - name: Generate Token
        id: generate-token
        uses: actions/create-github-app-token@v3
        with:
          app-id: ${{ secrets.ECOSYSTEM_CI_GITHUB_APP_ID }}
          private-key: ${{ secrets.ECOSYSTEM_CI_GITHUB_APP_PRIVATE_KEY }}
          repositories: |
            vite
            vite-ecosystem-ci

      - name: Trigger Preview Release (if Package Not Found)
        if: fromJSON(steps.check-package.outputs.result).exists == false
        uses: actions/github-script@v8
        id: trigger-preview-release
        env:
          PR_DATA: ${{ steps.get-pr-data.outputs.result }}
        with:
          github-token: ${{ steps.generate-token.outputs.token }}
          script: |
            const prData = JSON.parse(process.env.PR_DATA)
            console.log('Package not found, triggering preview release...')

            // Add label "trigger: preview" to the PR
            await github.rest.issues.addLabels({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: prData.num,
              labels: ['trigger: preview']
            })
            console.log('Added "trigger: preview" label.')

      - name: Wait for Preview Release Completion (if Package Not Found)
        if: fromJSON(steps.check-package.outputs.result).exists == false
        uses: actions/github-script@v8
        id: wait-preview-release
        env:
          PR_DATA: ${{ steps.get-pr-data.outputs.result }}
          REACTION: ${{ fromJSON(steps.check-package.outputs.result).reaction }}
        with:
          script: |
            const prData = JSON.parse(process.env.PR_DATA)
            const reaction = +process.env.REACTION
            const workflowFileName = 'preview-release.yml'
            const workflow = await github.rest.actions.getWorkflow({
              owner: context.repo.owner,
              repo: context.repo.repo,
              workflow_id: workflowFileName,
            })
            const workflowId = workflow.data.id
            console.log(`Waiting for workflow ID ${workflowId} to complete...`)

            const maxRetries = 60 // Wait up to 10 minutes
            const delay = 10000 // 10 seconds
            let completed = false

            for (let i = 0; i < maxRetries; i++) {
              const runsData = await github.rest.actions.listWorkflowRuns({
                owner: context.repo.owner,
                repo: context.repo.repo,
                workflow_id: workflowId,
                head_sha: prData.commit,
                per_page: 100,
                page: 1,
              })

              const runs = runsData.data.workflow_runs

              if (runs.length > 0) {
                const latestRun = runs[0]
                console.log(`Latest run status: ${latestRun.status}, conclusion: ${latestRun.conclusion}`)
                if (latestRun.status === 'completed') {
                  if (latestRun.conclusion === 'success') {
                    console.log('Preview release workflow completed successfully.')
                    completed = true
                    break
                  } else if (latestRun.conclusion === 'skipped') {
                   // noop
                  } else {
                    throw new Error('Preview Release workflow failed.')
                  }
                }
              }

              console.log(`Retrying... (${i + 1}/${maxRetries})`)
              await new Promise(resolve => setTimeout(resolve, delay))
            }

            if (!completed) {
              throw new Error('Preview Release workflow did not complete in time.')
            }

            // Remove the 'rocket' reaction
            if (reaction) {
              await github.rest.reactions.deleteForIssueComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: context.payload.comment.id,
                reaction_id: reaction,
              })
              console.log('Removed "rocket" reaction.')
            }

      - name: Trigger Downstream Workflow
        uses: actions/github-script@v8
        id: trigger
        env:
          COMMENT: ${{ github.event.comment.body }}
          PR_DATA: ${{ steps.get-pr-data.outputs.result }}
        with:
          github-token: ${{ steps.generate-token.outputs.token }}
          script: |
            const comment = process.env.COMMENT.trim()
            const prData = JSON.parse(process.env.PR_DATA)

            const suite = comment.split('\n')[0].replace(/^\/ecosystem-ci run/, '').trim()

            await github.rest.actions.createWorkflowDispatch({
              owner: context.repo.owner,
              repo: 'vite-ecosystem-ci',
              workflow_id: 'ecosystem-ci-from-pr.yml',
              ref: 'main',
              inputs: {
                prNumber: '' + prData.num,
                branchName: prData.branchName,
                repo: prData.repo,
                commit: prData.commit,
                suite: suite === '' ? '-' : suite
              }
            })
issue-close-require .github/workflows/issue-close-require.yml
Triggers
schedule
Runs on
ubuntu-slim
Jobs
close-issues
Actions
actions-cool/issues-helper
View raw YAML
name: Issue Close Require

on:
  schedule:
    - cron: "0 0 * * *"

jobs:
  close-issues:
    if: github.repository == 'vitejs/vite'
    runs-on: ubuntu-slim
    permissions:
      issues: write # for actions-cool/issues-helper to update issues
      pull-requests: write # for actions-cool/issues-helper to update PRs
    steps:
      - name: needs reproduction
        uses: actions-cool/issues-helper@200c78641dbf33838311e5a1e0c31bbdb92d7cf0 # v3
        with:
          actions: "close-issues"
          token: ${{ secrets.GITHUB_TOKEN }}
          labels: "needs reproduction"
          inactive-day: 3
issue-labeled .github/workflows/issue-labeled.yml
Triggers
issues
Runs on
ubuntu-slim
Jobs
reply-labeled
Actions
actions-cool/issues-helper, actions-cool/issues-helper, actions-cool/issues-helper
View raw YAML
name: Issue Labeled

on:
  issues:
    types: [labeled]

jobs:
  reply-labeled:
    if: github.repository == 'vitejs/vite'
    runs-on: ubuntu-slim
    permissions:
      issues: write # for actions-cool/issues-helper to update issues
      pull-requests: write # for actions-cool/issues-helper to update PRs
    steps:
      - name: contribution welcome
        if: github.event.label.name == 'contribution welcome' || github.event.label.name == 'help wanted'
        uses: actions-cool/issues-helper@200c78641dbf33838311e5a1e0c31bbdb92d7cf0 # v3
        with:
          actions: "remove-labels"
          token: ${{ secrets.GITHUB_TOKEN }}
          issue-number: ${{ github.event.issue.number }}
          labels: "pending triage, needs reproduction"

      - name: remove pending
        if: (github.event.label.name == 'enhancement' || contains(github.event.label.description, '(priority)')) && contains(github.event.issue.labels.*.name, 'pending triage')
        uses: actions-cool/issues-helper@200c78641dbf33838311e5a1e0c31bbdb92d7cf0 # v3
        with:
          actions: "remove-labels"
          token: ${{ secrets.GITHUB_TOKEN }}
          issue-number: ${{ github.event.issue.number }}
          labels: "pending triage"

      - name: needs reproduction
        if: github.event.label.name == 'needs reproduction'
        uses: actions-cool/issues-helper@200c78641dbf33838311e5a1e0c31bbdb92d7cf0 # v3
        with:
          actions: "create-comment, remove-labels"
          token: ${{ secrets.GITHUB_TOKEN }}
          issue-number: ${{ github.event.issue.number }}
          body: |
            Hello @${{ github.event.issue.user.login }}. Please provide a [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) using a GitHub repository or [StackBlitz](https://vite.new). Issues marked with `needs reproduction` will be closed if they have no activity within 3 days.
          labels: "pending triage"
issue-template-check .github/workflows/issue-template-check.yml
Triggers
issues
Runs on
ubuntu-latest, ubuntu-latest
Jobs
evaluate-issue, post-results
Actions
warpdotdev/oz-agent-action
View raw YAML
name: Issue Template Check

on:
  issues:
    types: [opened]

jobs:
  evaluate-issue:
    if: "!github.event.issue.pull_request"
    runs-on: ubuntu-latest
    permissions:
      contents: read
      issues: read
      pull-requests: read
    outputs:
      agent_output: ${{ steps.agent.outputs.agent_output }}
      template_type: ${{ steps.detect.outputs.template_type }}
      skip: ${{ steps.detect.outputs.skip }}
    steps:
      - uses: actions/checkout@v6

      - name: Detect issue type
        id: detect
        uses: actions/github-script@v8
        with:
          script: |
            const labels = context.payload.issue.labels.map(l => l.name);
            const issueType = context.payload.issue.type?.name;

            if (issueType === 'Bug') {
              core.setOutput('template_type', 'bug_report');
              core.setOutput('skip', 'false');
            } else if (issueType === 'Feature') {
              core.setOutput('template_type', 'feature_request');
              core.setOutput('skip', 'false');
            } else if (labels.includes('documentation')) {
              core.setOutput('template_type', 'docs');
              core.setOutput('skip', 'false');
            } else {
              core.info('Issue was not created from a recognized template. Skipping.');
              core.setOutput('template_type', 'unknown');
              core.setOutput('skip', 'true');
            }

      - uses: warpdotdev/oz-agent-action@1c023d0799f42be182644ced823d372a5ddddb40 # v1
        if: steps.detect.outputs.skip == 'false'
        id: agent
        with:
          prompt: |
            You are an issue reviewer for the Vite project.

            The issue template type detected is: ${{ steps.detect.outputs.template_type }}

            Read the matching issue template from the checked-out repository at:
            .github/ISSUE_TEMPLATE/${{ steps.detect.outputs.template_type }}.yml

            Then evaluate the following issue to determine if it faithfully follows that template.

            Issue title: ${{ github.event.issue.title }}
            Issue body:
            ${{ github.event.issue.body }}

            Here is a summary of the required fields per template type:

            **bug_report** required fields:
            1. Describe the bug (required) - A clear and concise description, not vague or just a generic error message
            2. Reproduction (required) - A valid link to a reproduction (vite.new or GitHub repo URL), not empty or plain text
            3. Steps to reproduce - Steps needed to reproduce (optional)
            4. System Info (required) - Output of the envinfo command, must look like actual system/envinfo output
            5. Used Package Manager (required) - One of: npm, yarn, pnpm, bun
            6. Logs - Optional error logs
            7. Validations (required) - All checkboxes must be checked

            **feature_request** required fields:
            1. Description (required) - Clear and concise description of the problem and use cases
            2. Suggested solution (required) - A proposed implementation or approach. If it suggests a new option, check against "Think Before Adding Yet Another Option" in the CONTRIBUTING.md
            3. Alternative - Alternative solutions considered (optional)
            4. Additional context - Any other context (optional)
            5. Validations (required) - All checkboxes must be checked

            **docs** required fields:
            1. Documentation is - Checkboxes indicating the issue type: Missing, Outdated, Confusing, Not sure (optional but at least one should be checked)
            2. Explain in Detail (required) - A clear description of the documentation issue
            3. Your Suggestion for Changes (required) - What should be changed
            4. Reproduction - Optional link via vite.new or GitHub repo
            5. Steps to reproduce - Optional reproduction steps

            Evaluate the issue against the criteria for its detected template type. Focus on whether the required fields are present and substantive (not empty placeholders or placeholder text).

            Respond with ONLY a JSON object (no markdown fencing) with these fields:
            - "template": the template type that was checked
            - "compliant": true/false
            - "missing": an array of strings describing what is missing or inadequate (empty array if compliant)
            - "comment": a polite, helpful comment to post if non-compliant, formatted in GitHub markdown. Address the user by their username @${{ github.event.issue.user.login }}. Ask them to update the issue with the missing information. Reference the specific template they should follow. Be concise.
          output_format: json
          warp_api_key: ${{ secrets.WARP_API_KEY }}
          profile: ${{ vars.WARP_AGENT_PROFILE || '' }}

  post-results:
    needs: evaluate-issue
    if: needs.evaluate-issue.outputs.skip == 'false' && needs.evaluate-issue.outputs.agent_output
    runs-on: ubuntu-latest
    permissions:
      contents: read
      issues: write
    steps:
      - name: Write result to summary
        uses: actions/github-script@v8
        env:
          TEMPLATE_TYPE: ${{ needs.evaluate-issue.outputs.template_type }}
          AGENT_OUTPUT: ${{ needs.evaluate-issue.outputs.agent_output }}
        with:
          script: |
            const output = process.env.AGENT_OUTPUT;
            const templateType = process.env.TEMPLATE_TYPE;

            try {
              // The agent outputs streaming JSON format with multiple lines
              // We need to extract the last line with type:"agent" and parse its text field
              const lines = output.trim().split('\n');
              let agentText = null;
              for (const line of lines) {
                try {
                  const parsed = JSON.parse(line);
                  if (parsed.type === 'agent' && parsed.text) {
                    agentText = parsed.text;
                  }
                } catch (e) {}
              }

              if (agentText) {
                await core.summary
                  .addHeading(`Issue Template Check (${templateType})`)
                  .addCodeBlock(agentText, 'json')
                  .write();
              } else {
                core.setFailed('No agent output found in response');
              }
            } catch (e) {
              core.setFailed(`Failed to write summary: ${e.message}`);
            }
lock-closed-issues perms .github/workflows/lock-closed-issues.yml
Triggers
schedule
Runs on
ubuntu-slim
Jobs
action
Actions
actions-cool/issues-helper
View raw YAML
name: Lock Closed Issues

on:
  schedule:
    - cron: "0 0 * * *"

permissions:
  issues: write

jobs:
  action:
    if: github.repository == 'vitejs/vite'
    runs-on: ubuntu-slim
    steps:
      - uses: actions-cool/issues-helper@200c78641dbf33838311e5a1e0c31bbdb92d7cf0 # v3
        with:
          actions: "lock-issues"
          token: ${{ secrets.GITHUB_TOKEN }}
          #body: |
          #  This issue has been locked since it has been closed for more than 14 days.
          #
          #  If you have found a concrete bug or regression related to it, please open a new [bug report](https://github.com/vitejs/vite/issues/new/choose) with a reproduction against the latest Vite version. If you have any other comments you should join the chat at [Vite Land](https://chat.vite.dev) or create a new [discussion](https://github.com/vitejs/vite/discussions).
          issue-state: closed
          inactive-day: 14
preview-release perms .github/workflows/preview-release.yml
Triggers
push, pull_request
Runs on
ubuntu-latest
Jobs
preview
Actions
pnpm/action-setup
Commands
  • yq '.onlyBuiltDependencies = []' -i pnpm-workspace.yaml
  • pnpm install
  • pnpm build
  • pnpm build
  • pnpm dlx pkg-pr-new@0.0 publish --pnpm './packages/vite' './packages/plugin-legacy' --packageManager=pnpm,npm,yarn --commentWithDev
View raw YAML
name: Preview release

env:
  # install playwright binary manually (because pnpm only runs install script once)
  PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"

permissions:
  pull-requests: write

on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, synchronize, labeled]

jobs:
  preview:
    if: >
      github.repository == 'vitejs/vite' &&
      (github.event_name == 'push' ||
      (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'trigger: preview')))
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Install pnpm
        uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0

      - name: Set node version to 24
        uses: actions/setup-node@v6
        with:
          node-version: 24
          registry-url: https://registry.npmjs.org/
          # disable cache, to avoid cache poisoning (https://docs.zizmor.sh/audits/#cache-poisoning)
          package-manager-cache: false

      - name: Disallow installation scripts
        run: yq '.onlyBuiltDependencies = []' -i pnpm-workspace.yaml

      - name: Install deps
        run: pnpm install
        env:
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"

      - name: Build Vite core
        working-directory: ./packages/vite
        run: pnpm build

      - name: Build plugin-legacy
        working-directory: ./packages/plugin-legacy
        run: pnpm build

      - run: pnpm dlx pkg-pr-new@0.0 publish --pnpm './packages/vite' './packages/plugin-legacy' --packageManager=pnpm,npm,yarn --commentWithDev
publish .github/workflows/publish.yml
Triggers
push
Runs on
ubuntu-latest
Jobs
publish
Actions
pnpm/action-setup
Commands
  • yq '.onlyBuiltDependencies = []' -i pnpm-workspace.yaml
  • pnpm install
  • npm i -g npm@^11.5.2 && pnpm run ci-publish "$REF_NAME"
View raw YAML
name: Publish Package

on:
  push:
    tags:
      - "v*" # Push events to matching v*, i.e. v1.0, v20.15.10
      - "plugin-*" # Push events to matching plugin-*, i.e. plugin-(vue|vue-jsx|react|legacy)@1.0.0
      - "create-vite*" # # Push events to matching create-vite*, i.e. create-vite@1.0.0

jobs:
  publish:
    # prevents this action from running on forks
    if: github.repository == 'vitejs/vite'
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write
    environment: Release
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Install pnpm
        uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0

      - name: Set node version to 24
        uses: actions/setup-node@v6
        with:
          node-version: 24
          registry-url: https://registry.npmjs.org/
          # disable cache, to avoid cache poisoning (https://docs.zizmor.sh/audits/#cache-poisoning)
          package-manager-cache: false

      - name: Disallow installation scripts
        run: yq '.onlyBuiltDependencies = []' -i pnpm-workspace.yaml

      - name: Install deps
        run: pnpm install
        env:
          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"

      - name: Publish package
        run: npm i -g npm@^11.5.2 && pnpm run ci-publish "$REF_NAME"
        env:
          REF_NAME: ${{ github.ref_name }}
pull-request-template-check .github/workflows/pull-request-template-check.yml
Triggers
pull_request_target
Runs on
ubuntu-latest, ubuntu-latest
Jobs
evaluate-pr, post-results
Actions
warpdotdev/oz-agent-action
View raw YAML
name: Pull Request Template Check

# SAFETY: pull_request_target is used here because:
# - The workflow does NOT check out PR code (actions/checkout checks out the base branch)
# - Only PR metadata (title, body) from the event payload is read
# - No PR-supplied code is executed
on:
  pull_request_target:
    types: [opened]

jobs:
  evaluate-pr:
    if: github.repository == 'vitejs/vite'
    runs-on: ubuntu-latest
    permissions:
      contents: read
      issues: read
      pull-requests: read
    outputs:
      agent_output: ${{ steps.agent.outputs.agent_output }}
    steps:
      - uses: actions/checkout@v6

      - uses: warpdotdev/oz-agent-action@827a9ad5438c195eb9d1d9a7acece3a8000be512 # v1
        id: agent
        with:
          prompt: |
            You are a pull request reviewer for the Vite project.

            Read the PR template from the checked-out repository at:
            .github/PULL_REQUEST_TEMPLATE.md

            Then evaluate the following pull request to determine if it faithfully follows that template's guidelines.

            PR title: ${{ github.event.pull_request.title }}
            PR body:
            ${{ github.event.pull_request.body }}

            Based on the PR template, check for the following:

            1. **Description** (required) - A clear and concise description of what the PR solves
            2. **Issue reference** (required) - References to related issues (e.g. `fixes #123`)
            3. **Alternatives explored** (optional but encouraged) - Mention of other approaches considered
            4. **Acknowledgments** (required) - Evidence that the author has:
               - Read the Contributing Guidelines
               - Checked for duplicate PRs
               - Considered documentation updates
               - Included relevant tests (or explained why not)

            Evaluate the PR against these criteria. Focus on whether the required information is present and substantive (not empty placeholders or placeholder text).

            Respond with ONLY a JSON object (no markdown fencing) with these fields:
            - "compliant": true/false
            - "missing": an array of strings describing what is missing or inadequate (empty array if compliant)
            - "comment": a polite, helpful comment to post if non-compliant, formatted in GitHub markdown. Address the user by their username @${{ github.event.pull_request.user.login }}. Ask them to update the PR with the missing information. Reference the PR template they should follow. Be concise.
          output_format: json
          warp_api_key: ${{ secrets.WARP_API_KEY }}
          profile: ${{ vars.WARP_AGENT_PROFILE || '' }}

  post-results:
    needs: evaluate-pr
    if: needs.evaluate-pr.outputs.agent_output
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    steps:
      - name: Write result to summary
        uses: actions/github-script@v8
        env:
          AGENT_OUTPUT: ${{ needs.evaluate-pr.outputs.agent_output }}
        with:
          script: |
            const output = process.env.AGENT_OUTPUT;

            try {
              // The agent outputs streaming JSON format with multiple lines
              // We need to extract the last line with type:"agent" and parse its text field
              const lines = output.trim().split('\n');
              let agentText = null;
              for (const line of lines) {
                try {
                  const parsed = JSON.parse(line);
                  if (parsed.type === 'agent' && parsed.text) {
                    agentText = parsed.text;
                  }
                } catch (e) {}
              }

              if (agentText) {
                await core.summary
                  .addHeading('Pull Request Template Check')
                  .addCodeBlock(agentText, 'json')
                  .write();
              } else {
                core.setFailed('No agent output found in response');
              }
            } catch (e) {
              core.setFailed(`Failed to write summary: ${e.message}`);
            }
release-tag .github/workflows/release-tag.yml
Triggers
push
Runs on
ubuntu-slim
Jobs
release
Actions
yyx990803/release-tag
Commands
  • # skip if alpha if [[ $GITHUB_REF_NAME =~ alpha ]]; then exit 0 fi # matching v2.0.0 / v2.0.0-beta.8 etc if [[ $GITHUB_REF_NAME =~ ^v.+ ]]; then pkgName="vite" else # `%@*` truncates @ and version number from the right side. # https://stackoverflow.com/questions/9532654/expression-after-last-specific-character pkgName=${GITHUB_REF_NAME%@*} fi echo "pkgName=$pkgName" >> $GITHUB_OUTPUT
View raw YAML
name: Add GitHub Release Tag

on:
  push:
    tags:
      - "v*" # Push events to matching v*, i.e. v1.0, v20.15.10
      - "plugin-*" # Push events to matching plugin-*, i.e. plugin-(vue|vue-jsx|react|legacy)@1.0.0
      - "create-vite*" # # Push events to matching create-vite*, i.e. create-vite@1.0.0

# $GITHUB_REF_NAME - https://docs.github.com/en/actions/reference/workflows-and-actions/variables#default-environment-variables

jobs:
  release:
    if: github.repository == 'vitejs/vite'
    runs-on: ubuntu-slim
    permissions:
      contents: write # for yyx990803/release-tag to create a release tag
    steps:
      - uses: actions/checkout@v6

      - name: Get pkgName for tag
        id: tag
        run: |
          # skip if alpha
          if [[ $GITHUB_REF_NAME =~ alpha ]]; then
            exit 0
          fi

          # matching v2.0.0 / v2.0.0-beta.8 etc
          if [[ $GITHUB_REF_NAME =~ ^v.+ ]]; then
            pkgName="vite"
          else
            # `%@*` truncates @ and version number from the right side.
            # https://stackoverflow.com/questions/9532654/expression-after-last-specific-character
            pkgName=${GITHUB_REF_NAME%@*}
          fi

          echo "pkgName=$pkgName" >> $GITHUB_OUTPUT

      - name: Create Release for Tag
        # only run if tag is not alpha
        if: steps.tag.outputs.pkgName
        id: release_tag
        uses: yyx990803/release-tag@8cccf7c5aa332d71d222df46677f70f77a8d2dc0 # v1.0.0
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          body: |
            Please refer to [CHANGELOG.md](https://github.com/vitejs/vite/blob/${{ github.ref_name }}/packages/${{ steps.tag.outputs.pkgName }}/CHANGELOG.md) for details.
semantic-pull-request .github/workflows/semantic-pull-request.yml
Triggers
pull_request_target
Runs on
ubuntu-slim
Jobs
main
Actions
amannn/action-semantic-pull-request
View raw YAML
name: Semantic Pull Request

on:
  pull_request_target:
    types:
      - opened
      - edited
      - synchronize

jobs:
  main:
    if: github.repository == 'vitejs/vite'
    runs-on: ubuntu-slim
    name: Semantic Pull Request
    permissions:
      pull-requests: read
    steps:
      - name: Validate PR title
        uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6
        with:
          subjectPattern: ^(?![A-Z]).+$
          subjectPatternError: |
            The subject "{subject}" found in the pull request title "{title}"
            didn't match the configured pattern. Please ensure that the subject
            doesn't start with an uppercase character.
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}