Skip to content
Merged
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
6 changes: 5 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ jobs:

- name: Verify installation
shell: bash
run: vp --version | grep -F "${{ steps.preview.outputs.version }}"
run: |
vp env current
vp i -g cowsay@1.6.0
vp env doctor
vp --version | grep -F "${{ steps.preview.outputs.version }}"

test-node-version:
strategy:
Expand Down
41 changes: 39 additions & 2 deletions dist/azure/index.mjs

Large diffs are not rendered by default.

153 changes: 95 additions & 58 deletions dist/index.mjs

Large diffs are not rendered by default.

141 changes: 130 additions & 11 deletions gitlab/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,99 @@ setup_vp_export_env() {
printf "\n" >> "$SETUP_VP_ENV_FILE"
}

setup_vp_read_bin_dir() {
awk '
{
separator = index($0, "\t")
if (separator == 0) next
key = substr($0, 1, separator - 1)
value = substr($0, separator + 1)
sub(/^[[:space:]]+/, "", value)
sub(/[[:space:]]+$/, "", value)
if (key == "data") data = value
if (key == "bin") bin = value
if (key == "cache") cache = value
if (key == "config") config = value
if (key == "state") state = value
}
END {
if (data != "" && bin != "" && cache != "" && config != "" && state != "") {
print bin
exit 0
}
exit 1
}
' "$1"
}

setup_vp_read_installed_version() {
awk '
$1 == "vp" && $2 ~ /^v?[0-9]/ {
version = $2
sub(/^v/, "", version)
print version
exit
}
{
for (field = 1; field < NF; field++) {
if ($field == "Global:" && $(field + 1) ~ /^v?[0-9]/) {
version = $(field + 1)
sub(/^v/, "", version)
print version
exit
}
}
}
' "$1"
}

setup_vp_install_and_dump_dirs() {
bash -c '
set +u
setup_vp_installer_path="$1"
setup_vp_dirs_path="$2"
set --

# Run the sourced installer at the top level of this shell. The installer
# can then use its own errexit setting even when the caller checks the
# result in an if condition. Nounset is disabled only in this shell.
. "$setup_vp_installer_path"
setup_vp_installer_status=$?
if [ "$setup_vp_installer_status" -ne 0 ]; then
exit "$setup_vp_installer_status"
fi

setup_vp_shim_dir="${SHIM_DIR:-${INSTALL_DIR:-${VP_HOME:-$HOME/.vite-plus}}/bin}"
if [ ! -x "$setup_vp_shim_dir/vp" ]; then
exit 1
fi

"$setup_vp_shim_dir/vp" --version > "$setup_vp_dirs_path"
VP_DUMP_DIRS=1 "$setup_vp_shim_dir/vp" >> "$setup_vp_dirs_path"
' setup-vp-installer "$1" "$2"
}

setup_vp_install_viteplus_from() {
setup_vp_url="$1"
setup_vp_download "$setup_vp_url" "$setup_vp_install_tmp" || return 1

if [ -n "$setup_vp_pr_version" ]; then
VP_VERSION="$SETUP_VP_VERSION" \
VITE_PLUS_VERSION="$SETUP_VP_VERSION" \
VP_PR_VERSION="$setup_vp_pr_version" \
bash "$setup_vp_install_tmp"
else
VP_VERSION="$SETUP_VP_VERSION" \
VITE_PLUS_VERSION="$SETUP_VP_VERSION" \
(
export VP_VERSION="$SETUP_VP_VERSION"
export VITE_PLUS_VERSION="$SETUP_VP_VERSION"
if [ -n "$setup_vp_pr_version" ]; then
export VP_PR_VERSION="$setup_vp_pr_version"
fi

if [ "$setup_vp_detect_dirs" = "true" ]; then
: > "$setup_vp_dirs_tmp"
export VP_VPDIRS_AWARE="1"
# Source the official installer so its VpDirs-resolved shim remains
# available long enough to ask the installed payload for its directories.
setup_vp_install_and_dump_dirs "$setup_vp_install_tmp" "$setup_vp_dirs_tmp"
else
bash "$setup_vp_install_tmp"
fi
fi
)
}

setup_vp_try_install_urls() {
Expand Down Expand Up @@ -122,6 +201,23 @@ if [[ "$SETUP_VP_VERSION" =~ ^0\.0\.0-commit\.([0-9a-fA-F]{40})$ ]]; then
setup_vp_pr_version="${BASH_REMATCH[1]}"
fi

# VpDirs was added in Vite+ 0.3.0. Preview builds also contain it. For a
# dist-tag, probe the installed version before a missing VpDirs result selects
# the legacy layout.
setup_vp_detect_dirs="true"
setup_vp_check_installed_version="false"
if [ -z "$setup_vp_pr_version" ]; then
if [[ "$SETUP_VP_VERSION" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(-[0-9A-Za-z.-]+)?$ ]]; then
setup_vp_major=$((10#${BASH_REMATCH[1]}))
setup_vp_minor=$((10#${BASH_REMATCH[2]}))
if [ "$setup_vp_major" -eq 0 ] && [ "$setup_vp_minor" -lt 3 ]; then
setup_vp_detect_dirs="false"
fi
else
setup_vp_check_installed_version="true"
fi
fi

# Git ref that serves the install script for the requested version: the
# preview build's commit, or the `v<version>` release tag for an exact
# version. Dist-tags like "latest" do not map to a ref and keep the latest
Expand All @@ -133,12 +229,35 @@ elif [[ "$SETUP_VP_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; th
setup_vp_pinned_ref="v${SETUP_VP_VERSION}"
fi
setup_vp_install_tmp="$(mktemp "${TMPDIR:-/tmp}/setup-vp-install.XXXXXX")"
setup_vp_dirs_tmp="$(mktemp "${TMPDIR:-/tmp}/setup-vp-dirs.XXXXXX")"
setup_vp_runtime_dir="$(mktemp -d "${TMPDIR:-/tmp}/setup-vp-gitlab-runtime.XXXXXX")"
setup_vp_runtime_tmp="${setup_vp_runtime_dir}/index.mjs"
trap 'rm -f "$setup_vp_install_tmp" "$setup_vp_runtime_tmp"; rmdir "$setup_vp_runtime_dir" 2>/dev/null || true' EXIT
trap 'rm -f "$setup_vp_install_tmp" "$setup_vp_dirs_tmp" "$setup_vp_runtime_tmp"; rmdir "$setup_vp_runtime_dir" 2>/dev/null || true' EXIT

setup_vp_install_viteplus
export PATH="$HOME/.vite-plus/bin:$PATH"
if [ "$setup_vp_detect_dirs" = "true" ]; then
if ! setup_vp_bin_dir="$(setup_vp_read_bin_dir "$setup_vp_dirs_tmp")"; then
setup_vp_bin_dir=""
if [ "$setup_vp_check_installed_version" = "true" ]; then
setup_vp_installed_version="$(setup_vp_read_installed_version "$setup_vp_dirs_tmp")"
if [[ "$setup_vp_installed_version" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(-[0-9A-Za-z.-]+)?$ ]]; then
setup_vp_major=$((10#${BASH_REMATCH[1]}))
setup_vp_minor=$((10#${BASH_REMATCH[2]}))
if [ "$setup_vp_major" -eq 0 ] && [ "$setup_vp_minor" -lt 3 ]; then
setup_vp_bin_dir="$HOME/.vite-plus/bin"
fi
fi
fi
if [ -z "$setup_vp_bin_dir" ]; then
echo "setup-vp: Vite+ was installed successfully, but setup-vp could not resolve its VpDirs." >&2
return 1 2>/dev/null || exit 1
fi
fi
else
# Vite+ releases before VpDirs use the monolithic layout.
setup_vp_bin_dir="$HOME/.vite-plus/bin"
fi
export PATH="$setup_vp_bin_dir:$PATH"
setup_vp_export_env PATH "$PATH"

if ! command -v node >/dev/null 2>&1; then
Expand Down
109 changes: 101 additions & 8 deletions src/azure/install-viteplus.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
import { describe, expect, it, vi } from "vite-plus/test";
import { writeFileSync } from "node:fs";
import { installVitePlus } from "./install-viteplus.js";

function writeDirsFile(env: Record<string, string>, bin: string): void {
writeFileSync(
env.SETUP_VP_DIRS_FILE,
[
"data\t/test/data",
`bin\t${bin}`,
"cache\t/test/cache",
"config\t/test/config",
"state\t/test/state",
].join("\n"),
);
}

describe("installVitePlus", () => {
it("uses PowerShell installers on Windows and bash installers on Unix", async () => {
const calls: NodeJS.Platform[] = [];
const runInstall = vi.fn(
(
_url: string,
_env: Record<string, string>,
platform: NodeJS.Platform = process.platform,
) => {
(_url: string, env: Record<string, string>, platform: NodeJS.Platform = process.platform) => {
calls.push(platform);
writeDirsFile(env, `/test/${platform}/bin`);
return 0;
},
);
Expand Down Expand Up @@ -39,13 +50,17 @@ describe("installVitePlus", () => {

it("installs exact versions with the release-tag script before the latest script", async () => {
// Fail every attempt so the full URL order is observable.
const runInstall = vi.fn((_url: string) => 1);
const runInstall = vi.fn((_url: string, _env: Record<string, string>) => 1);
const warnings: string[] = [];

await expect(
installVitePlus("0.2.9", {
platform: "linux",
env: { PATH: "" },
env: {
PATH: "",
VP_VPDIRS_AWARE: "1",
SETUP_VP_DIRS_FILE: "/tmp/stale-vp-dirs",
},
prependPath: () => undefined,
sleep: async () => undefined,
runInstall,
Expand All @@ -58,10 +73,16 @@ describe("installVitePlus", () => {
expect(urls[1]).toContain("jsdelivr");
expect(urls[4]).toBe("https://viteplus.dev/install.sh");
expect(warnings.some((message) => message.includes("Falling back to the latest"))).toBe(true);
const installEnv = runInstall.mock.calls[0]?.[1] as Record<string, string>;
expect(installEnv.VP_VPDIRS_AWARE).toBeUndefined();
expect(installEnv.SETUP_VP_DIRS_FILE).toBeUndefined();
});

it("routes pkg.pr.new commit builds through VP_PR_VERSION", async () => {
const runInstall = vi.fn(() => 0);
const runInstall = vi.fn((_url: string, env: Record<string, string>) => {
writeDirsFile(env, "/test/data/bin");
return 0;
});
const sha = "a".repeat(40);

await installVitePlus(`0.0.0-commit.${sha}`, {
Expand All @@ -77,5 +98,77 @@ describe("installVitePlus", () => {
[string, Record<string, string>, NodeJS.Platform?]
>;
expect(installCalls[0]?.[1]?.VP_PR_VERSION).toBe(sha);
expect(installCalls[0]?.[1]?.VP_VPDIRS_AWARE).toBe("1");
expect(installCalls[0]?.[1]?.SETUP_VP_DIRS_FILE).toMatch(/setup-vp-dirs-.*\.txt$/);
});

it("uses the installed version to resolve the latest dist-tag", async () => {
const prependPath = vi.fn();
const env = { HOME: "/home/runner", PATH: "/usr/bin" };
const runInstall = vi.fn((_url: string, installEnv: Record<string, string>) => {
writeFileSync(installEnv.SETUP_VP_DIRS_FILE, "vp v0.2.9\n");
return 0;
});

await installVitePlus("latest", {
platform: "linux",
env,
prependPath,
sleep: async () => undefined,
runInstall,
logWarningFn: () => undefined,
});

expect(prependPath).toHaveBeenCalledWith("/home/runner/.vite-plus/bin");
expect(env.PATH).toBe("/home/runner/.vite-plus/bin:/usr/bin");
});

it.each([
{ version: "0.3.0", output: "vp v0.2.9\n" },
{ version: `0.0.0-commit.${"a".repeat(40)}`, output: "bin\t/test/data/bin\n" },
{ version: "latest", output: "vp v0.3.0\n" },
])("fails when $version does not report valid VpDirs", async ({ version, output }) => {
const prependPath = vi.fn();
const runInstall = vi.fn((_url: string, env: Record<string, string>) => {
if (output !== undefined) writeFileSync(env.SETUP_VP_DIRS_FILE, output);
return 0;
});

await expect(
installVitePlus(version, {
platform: "linux",
env: { PATH: "/usr/bin" },
prependPath,
sleep: async () => undefined,
runInstall,
logWarningFn: () => undefined,
}),
).rejects.toThrow(
"Vite+ was installed successfully, but setup-vp could not resolve its VpDirs.",
);

expect(runInstall).toHaveBeenCalledTimes(1);
expect(prependPath).not.toHaveBeenCalled();
});

it("prepends the bin directory reported by the installed payload", async () => {
const prependPath = vi.fn();
const env = { PATH: "/usr/bin" };
const runInstall = vi.fn((_url: string, installEnv: Record<string, string>) => {
writeDirsFile(installEnv, "/test/data/bin");
return 0;
});

await installVitePlus("latest", {
platform: "linux",
env,
prependPath,
sleep: async () => undefined,
runInstall,
logWarningFn: () => undefined,
});

expect(prependPath).toHaveBeenCalledWith("/test/data/bin");
expect(env.PATH).toBe("/test/data/bin:/usr/bin");
});
});
Loading
Loading