Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"customManagers": [
{
"customType": "regex",
"fileMatch": ["^src/install-sfw\\.ts$", "^src/gitlab/install-sfw\\.ts$"],
"fileMatch": ["^src/install-sfw\\.ts$", "^src/ci/install-sfw\\.ts$"],
"matchStrings": ["const SFW_VERSION = \"(?<currentValue>v[^\"]+)\";"],
"depNameTemplate": "SocketDev/sfw-free",
"datasourceTemplate": "github-releases"
Expand Down
36 changes: 36 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,42 @@ jobs:
fi
echo "OK: composed sfw blocked lodahs (exit $CODE, block-line found)"

test-azure-runtime:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- name: Setup Vite+
uses: ./
with:
run-install: false
cache: false

- name: Build portable bundles
run: vp run build

- name: Verify Azure runtime invalid phase smoke test
shell: bash
run: |
if node dist/azure/index.mjs invalid-phase; then
echo "::error::Azure runtime accepted an invalid phase"
exit 1
fi

- name: Verify bootstrap syntax (Unix)
if: runner.os != 'Windows'
run: bash -n azure/bootstrap.sh gitlab/bootstrap.sh

- name: Verify bootstrap syntax (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
[scriptblock]::Create((Get-Content -Raw azure/bootstrap.ps1)) > $null

build:
runs-on: ubuntu-latest
# This job verifies the action's own artifacts (dist/ committed and up to
Expand Down
9 changes: 7 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ This file provides guidance to coding agents working in this repository.
## Guidelines

- Do not commit changes automatically. Wait for an explicit user request to commit.
- Keep `dist/index.mjs` in sync with source changes by running `vp run build` before committing.
- Keep `dist/index.mjs`, `dist/gitlab/index.mjs`, and `dist/azure/index.mjs` in sync with source changes by running `vp run build` before committing.

## Project Overview

GitHub Action to set up [Vite+](https://viteplus.dev) (`vp`) with dependency caching support. The action installs Vite+ globally, can set up Node.js via `vp env use`, optionally configures registry auth, restores/saves dependency cache, and can run `vp install` with optional Socket Firewall Free (`sfw`) wrapping.
GitHub Action to set up [Vite+](https://viteplus.dev) (`vp`) with dependency caching support. The action installs Vite+ globally, can set up Node.js via `vp env use`, optionally configures registry auth, restores/saves dependency cache, and can run `vp install` with optional Socket Firewall Free (`sfw`) wrapping. GitLab and Azure Pipelines entry points reuse a dependency-light portable runtime under `src/ci/`.

## Commands

Expand Down Expand Up @@ -60,6 +60,11 @@ The action has main and post execution phases. Both are served by `src/index.ts`
- `src/run-install.ts` - Execute `vp install` entries with optional cwd/args.
- `src/install-sfw.ts` - Install or reuse Socket Firewall Free for wrapped installs.
- `src/utils.ts` - Lock file detection, package-manager cache paths, and shared helpers.
- `src/ci/*` - Shared dependency-light primitives for GitLab and Azure runtimes.
- `src/gitlab/*` - GitLab runtime adapters around `src/ci/*`.
- `src/azure/*` - Azure Pipelines runtime and logging-command adapters.
- `azure/setup-vp.yml` - Azure step template.
- `gitlab/setup-vp.yml` - GitLab remote template.

### Lock File Detection

Expand Down
73 changes: 71 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# setup-vp

GitHub Action and GitLab CI/CD remote template to set up [Vite+](https://viteplus.dev) (`vp`).
GitHub Action, GitLab CI/CD remote template, and Azure Pipelines step template to set up [Vite+](https://viteplus.dev) (`vp`).

## Features

Expand All @@ -11,6 +11,7 @@ GitHub Action and GitLab CI/CD remote template to set up [Vite+](https://viteplu
- Optionally wrap `vp install` with [Socket Firewall Free (`sfw`)](https://docs.socket.dev/docs/socket-firewall-free) to block malicious dependencies
- Support for all major package managers (npm, pnpm, yarn, bun)
- GitLab CI/CD support through a reusable `include:remote` template
- Azure Pipelines support through a reusable step template and compiled runtime

## Usage

Expand Down Expand Up @@ -494,6 +495,74 @@ test:
- The GitLab template does not set up Node.js. Use a Node image such as `node:24`, or install Node.js before extending `.setup-vp`.
- The GitLab template intentionally does not expose `cache` or `cache-dependency-path` inputs. GitLab restores job cache before `before_script`, so this template cannot compute cache paths during setup and restore them for the same job. Configure GitLab `cache:` directly on the job when needed.

## Azure Pipelines

setup-vp also provides an Azure Pipelines step template hosted from this GitHub repository. Azure cannot execute the GitHub Action bundle directly, so the template downloads a compiled runtime (`dist/azure/index.mjs`) and runs it in `prepare` and `finalize` phases around Azure's native `Cache@2` task.

See [Azure Pipelines integration notes](rfcs/azure-pipelines-integration.md) for the design background, parity table, and cache semantics.

### Basic Azure Usage

Create a GitHub service connection named `github`, then reference the template from this repository:

```yaml
resources:
repositories:
- repository: setupVp
type: github
endpoint: github
name: voidzero-dev/setup-vp
ref: refs/tags/v1.16.0

pool:
vmImage: ubuntu-latest

steps:
- checkout: self

- template: azure/setup-vp.yml@setupVp
parameters:
setupRef: v1.16.0
nodeVersion: 24.x
cache: true
runInstall: true

- script: vp run test
```

Pin `ref` and `setupRef` to the same tag or commit SHA for strict reproducibility. The moving `v1` tag is supported for convenience but is not immutable.

### Azure Parameters

| Parameter | Default | Description |
| --------------------- | -------- | ------------------------------------------------------------------------- |
| `version` | `latest` | Vite+ version/dist-tag passed to the official installer. |
| `workingDirectory` | `.` | Project directory for lock detection and default `vp install`. |
| `runInstall` | `true` | Run `vp install`; accepts boolean or object/list with `cwd` and `args`. |
| `sfw` | `false` | Wrap `vp install` with Socket Firewall Free. |
| `registryUrl` | | Optional registry URL for a temporary `.npmrc`. |
| `scope` | | Optional npm registry scope. |
| `setupRef` | `v1` | Ref used to download bootstrap scripts and `dist/azure/index.mjs`. |
| `nodeVersion` | `24.x` | Passed to `UseNode@1`; an empty string skips Node setup. |
| `cache` | `false` | Enable Azure `Cache@2` around the package-manager cache directory. |
| `cacheDependencyPath` | | Explicit lock file relative to `workingDirectory`; otherwise auto-detect. |

### Azure Job Variables

| Variable | Purpose |
| ---------------------------- | --------------------------------------------------------------------- |
| `SETUP_VP_INSTALLED_VERSION` | Installed global Vite+ version (`unknown` when parsing fails). |
| `SETUP_VP_CACHE_HIT` | `true`, `inexact`, or `false` from `Cache@2` when caching is enabled. |

`vp`, `NPM_CONFIG_USERCONFIG`, and `PNPM_CONFIG_USERCONFIG` are available to later steps in the same job. Define `NODE_AUTH_TOKEN` as an Azure secret pipeline variable when private registry auth is required; the template maps it into both finalize tasks.

### Azure Notes

- The template supports Microsoft-hosted Linux, macOS, and Windows agents.
- `Cache@2` restores before `vp install` and saves automatically in a post-job step.
- Missing lock files or cache paths degrade to a warning and `SETUP_VP_CACHE_READY=false` instead of failing setup.
- For Azure Artifacts feeds, compose with Azure's `npmAuthenticate` task and/or pass `registryUrl` plus `NODE_AUTH_TOKEN`.

## Example Workflow

```yaml
Expand Down Expand Up @@ -550,7 +619,7 @@ vp install
### Before Committing

- Run `vp run check:fix` and `vp run build`
- Generated files under `dist/` must be committed, including `dist/index.mjs` for the GitHub Action and `dist/gitlab/index.mjs` for the GitLab template
- Generated files under `dist/` must be committed, including `dist/index.mjs` for the GitHub Action, `dist/gitlab/index.mjs` for the GitLab template, and `dist/azure/index.mjs` for the Azure Pipelines runtime
- Pre-commit hooks (via husky + lint-staged) will automatically run `vp check --fix` on staged files via `vpx lint-staged`

### Releasing
Expand Down
40 changes: 40 additions & 0 deletions azure/bootstrap.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
$ErrorActionPreference = 'Stop'

# Azure step templates expand YAML from an external repository but do not check
# out bootstrap/runtime files onto the agent. Download the compiled runtime and
# execute its prepare phase, which installs Vite+ and emits cache metadata.

function Setup-VpDownload {
param(
[string]$Url,
[string]$OutFile
)

Invoke-WebRequest -Uri $Url -OutFile $OutFile -TimeoutSec 60
}

$setupRef = if ($env:SETUP_VP_SETUP_REF) { $env:SETUP_VP_SETUP_REF } else { 'v1' }
$runtimeOut = if ($env:SETUP_VP_RUNTIME_OUT) {
$env:SETUP_VP_RUNTIME_OUT
} else {
Join-Path $env:AGENT_TEMPDIRECTORY 'setup-vp-azure/dist/azure/index.mjs'
}

$runtimeDir = Split-Path -Parent $runtimeOut
$chunkDir = Split-Path -Parent $runtimeDir
New-Item -ItemType Directory -Path $runtimeDir -Force | Out-Null
New-Item -ItemType Directory -Path $chunkDir -Force | Out-Null

$runtimeUrl = "https://raw.githubusercontent.com/voidzero-dev/setup-vp/$setupRef/dist/azure/index.mjs"
Setup-VpDownload -Url $runtimeUrl -OutFile $runtimeOut

$runtimeText = Get-Content -LiteralPath $runtimeOut -Raw
$chunkMatches = [regex]::Matches($runtimeText, '[''"]\.\./([^''"]+\.mjs)[''"]')
$chunkNames = @($chunkMatches | ForEach-Object { $_.Groups[1].Value } | Sort-Object -Unique)
foreach ($chunkName in $chunkNames) {
$chunkUrl = "https://raw.githubusercontent.com/voidzero-dev/setup-vp/$setupRef/dist/$chunkName"
$chunkOut = Join-Path $chunkDir $chunkName
Setup-VpDownload -Url $chunkUrl -OutFile $chunkOut
}

& node $runtimeOut prepare
39 changes: 39 additions & 0 deletions azure/bootstrap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
set -euo pipefail

# Azure step templates expand YAML from an external repository but do not check
# out bootstrap/runtime files onto the agent. Download the compiled runtime and
# execute its prepare phase, which installs Vite+ and emits cache metadata.

setup_vp_download() {
setup_vp_url="$1"
setup_vp_out="$2"

if command -v curl >/dev/null 2>&1; then
curl -fsSL --connect-timeout 5 --max-time 60 "$setup_vp_url" -o "$setup_vp_out"
elif command -v wget >/dev/null 2>&1; then
wget -q -T 60 -t 2 -O "$setup_vp_out" "$setup_vp_url"
else
echo "setup-vp: curl or wget is required to download files." >&2
return 127
fi
}

SETUP_VP_SETUP_REF="${SETUP_VP_SETUP_REF:-v1}"
SETUP_VP_RUNTIME_OUT="${SETUP_VP_RUNTIME_OUT:-${TMPDIR:-/tmp}/setup-vp-azure/dist/azure/index.mjs}"
setup_vp_runtime_dir="$(dirname "$SETUP_VP_RUNTIME_OUT")"
setup_vp_chunk_dir="$(dirname "$setup_vp_runtime_dir")"
mkdir -p "$setup_vp_runtime_dir" "$setup_vp_chunk_dir"
chmod 600 "$SETUP_VP_RUNTIME_OUT" 2>/dev/null || true

setup_vp_runtime_url="https://raw.githubusercontent.com/voidzero-dev/setup-vp/${SETUP_VP_SETUP_REF}/dist/azure/index.mjs"
setup_vp_download "$setup_vp_runtime_url" "$SETUP_VP_RUNTIME_OUT"

while IFS= read -r setup_vp_chunk; do
setup_vp_chunk_name="${setup_vp_chunk#../}"
setup_vp_download \
"https://raw.githubusercontent.com/voidzero-dev/setup-vp/${SETUP_VP_SETUP_REF}/dist/${setup_vp_chunk_name}" \
"$setup_vp_chunk_dir/${setup_vp_chunk_name}"
done < <(grep -Eo "['\"]\.\./[^'\"]+\.mjs['\"]" "$SETUP_VP_RUNTIME_OUT" | tr -d "'\"" | sort -u)

node "$SETUP_VP_RUNTIME_OUT" prepare
123 changes: 123 additions & 0 deletions azure/setup-vp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
parameters:
- name: version
type: string
default: latest
- name: workingDirectory
type: string
default: .
- name: runInstall
type: object
default: true
- name: sfw
type: boolean
default: false
- name: registryUrl
type: string
default: ""
- name: scope
type: string
default: ""
- name: setupRef
type: string
default: v1
- name: nodeVersion
type: string
default: 24.x
- name: cache
type: boolean
default: false
- name: cacheDependencyPath
type: string
default: ""

steps:
- ${{ if ne(parameters.nodeVersion, '') }}:
- task: UseNode@1
displayName: Use Node.js
inputs:
version: ${{ parameters.nodeVersion }}

- powershell: |
$ErrorActionPreference = 'Stop'
$bootstrap = Join-Path $env:AGENT_TEMPDIRECTORY 'setup-vp-azure-bootstrap.ps1'
$base = "https://raw.githubusercontent.com/voidzero-dev/setup-vp/${{ parameters.setupRef }}/azure"
Invoke-WebRequest -Uri "$base/bootstrap.ps1" -OutFile $bootstrap -TimeoutSec 60
& $bootstrap
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
displayName: setup-vp prepare (Windows)
env:
SETUP_VP_VERSION: ${{ parameters.version }}
SETUP_VP_WORKING_DIRECTORY: ${{ parameters.workingDirectory }}
SETUP_VP_RUN_INSTALL: ${{ convertToJson(parameters.runInstall) }}
SETUP_VP_SFW: ${{ iif(eq(parameters.sfw, true), 'true', 'false') }}
SETUP_VP_REGISTRY_URL: ${{ parameters.registryUrl }}
SETUP_VP_SCOPE: ${{ parameters.scope }}
SETUP_VP_SETUP_REF: ${{ parameters.setupRef }}
SETUP_VP_CACHE: ${{ iif(eq(parameters.cache, true), 'true', 'false') }}
SETUP_VP_CACHE_DEPENDENCY_PATH: ${{ parameters.cacheDependencyPath }}
SETUP_VP_RUNTIME_OUT: $(Agent.TempDirectory)\setup-vp-azure\dist\azure\index.mjs

- bash: |
set -euo pipefail
bootstrap="$(Agent.TempDirectory)/setup-vp-azure-bootstrap.sh"
base="https://raw.githubusercontent.com/voidzero-dev/setup-vp/${{ parameters.setupRef }}/azure"
curl -fsSL --connect-timeout 5 --max-time 60 "$base/bootstrap.sh" -o "$bootstrap"
chmod +x "$bootstrap"
bash "$bootstrap"
condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT'))
displayName: setup-vp prepare (Unix)
env:
SETUP_VP_VERSION: ${{ parameters.version }}
SETUP_VP_WORKING_DIRECTORY: ${{ parameters.workingDirectory }}
SETUP_VP_RUN_INSTALL: ${{ convertToJson(parameters.runInstall) }}
SETUP_VP_SFW: ${{ iif(eq(parameters.sfw, true), 'true', 'false') }}
SETUP_VP_REGISTRY_URL: ${{ parameters.registryUrl }}
SETUP_VP_SCOPE: ${{ parameters.scope }}
SETUP_VP_SETUP_REF: ${{ parameters.setupRef }}
SETUP_VP_CACHE: ${{ iif(eq(parameters.cache, true), 'true', 'false') }}
SETUP_VP_CACHE_DEPENDENCY_PATH: ${{ parameters.cacheDependencyPath }}
SETUP_VP_RUNTIME_OUT: $(Agent.TempDirectory)/setup-vp-azure/dist/azure/index.mjs

- ${{ if eq(parameters.cache, true) }}:
- task: Cache@2
displayName: Cache Vite+ package-manager data
condition: and(succeeded(), eq(variables['SETUP_VP_CACHE_READY'], 'true'))
inputs:
key: '"vite-plus" | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(SETUP_VP_LOCK_TYPE)" | $(SETUP_VP_LOCK_FILE)'
restoreKeys: |
"vite-plus" | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(SETUP_VP_LOCK_TYPE)"
"vite-plus" | "$(Agent.OS)" | "$(Agent.OSArchitecture)"
path: $(SETUP_VP_CACHE_PATH)
cacheHitVar: SETUP_VP_CACHE_HIT

- powershell: |
$ErrorActionPreference = 'Stop'
node "$(Agent.TempDirectory)\setup-vp-azure\dist\azure\index.mjs" finalize
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
displayName: setup-vp finalize (Windows)
env:
SETUP_VP_VERSION: ${{ parameters.version }}
SETUP_VP_WORKING_DIRECTORY: ${{ parameters.workingDirectory }}
SETUP_VP_RUN_INSTALL: ${{ convertToJson(parameters.runInstall) }}
SETUP_VP_SFW: ${{ iif(eq(parameters.sfw, true), 'true', 'false') }}
SETUP_VP_REGISTRY_URL: ${{ parameters.registryUrl }}
Comment thread
tonoizer marked this conversation as resolved.
SETUP_VP_SCOPE: ${{ parameters.scope }}
NODE_AUTH_TOKEN: $(NODE_AUTH_TOKEN)
SETUP_VP_CACHE: ${{ iif(eq(parameters.cache, true), 'true', 'false') }}
SETUP_VP_CACHE_DEPENDENCY_PATH: ${{ parameters.cacheDependencyPath }}

- bash: |
set -euo pipefail
node "$(Agent.TempDirectory)/setup-vp-azure/dist/azure/index.mjs" finalize
condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT'))
displayName: setup-vp finalize (Unix)
env:
SETUP_VP_VERSION: ${{ parameters.version }}
SETUP_VP_WORKING_DIRECTORY: ${{ parameters.workingDirectory }}
SETUP_VP_RUN_INSTALL: ${{ convertToJson(parameters.runInstall) }}
SETUP_VP_SFW: ${{ iif(eq(parameters.sfw, true), 'true', 'false') }}
SETUP_VP_REGISTRY_URL: ${{ parameters.registryUrl }}
SETUP_VP_SCOPE: ${{ parameters.scope }}
NODE_AUTH_TOKEN: $(NODE_AUTH_TOKEN)
SETUP_VP_CACHE: ${{ iif(eq(parameters.cache, true), 'true', 'false') }}
SETUP_VP_CACHE_DEPENDENCY_PATH: ${{ parameters.cacheDependencyPath }}
Loading