mirror of
https://github.com/supabase/setup-cli.git
synced 2026-06-28 01:46:58 +00:00
Compare commits
4 Commits
v2.1.0
...
codex/npm-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9ad437f39 | ||
|
|
3c2f5e2ae3 | ||
|
|
365cb468b9 | ||
|
|
e0099b2bdb |
2
.github/workflows/dependabot.yml
vendored
2
.github/workflows/dependabot.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
|||||||
- name: Generate token
|
- name: Generate token
|
||||||
id: app-token
|
id: app-token
|
||||||
if: ${{ steps.meta.outputs.update-type == null || steps.meta.outputs.update-type == 'version-update:semver-patch' || steps.meta.outputs.update-type == 'version-update:semver-minor' }}
|
if: ${{ steps.meta.outputs.update-type == null || steps.meta.outputs.update-type == 'version-update:semver-patch' || steps.meta.outputs.update-type == 'version-update:semver-minor' }}
|
||||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
|
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||||
with:
|
with:
|
||||||
app-id: ${{ secrets.APP_ID }}
|
app-id: ${{ secrets.APP_ID }}
|
||||||
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
||||||
|
|||||||
4
.github/workflows/licensed.yml
vendored
4
.github/workflows/licensed.yml
vendored
@@ -71,7 +71,7 @@ jobs:
|
|||||||
- name: Setup Ruby
|
- name: Setup Ruby
|
||||||
id: setup-ruby
|
id: setup-ruby
|
||||||
if: steps.license-inputs.outputs.changed == 'true'
|
if: steps.license-inputs.outputs.changed == 'true'
|
||||||
uses: ruby/setup-ruby@7372622e62b60b3cb750dcd2b9e32c247ffec26a # v1.302.0
|
uses: ruby/setup-ruby@97ecb7b512899eb71ab1bf2310a624c6f1589ac6 # v1.308.0
|
||||||
with:
|
with:
|
||||||
ruby-version: ruby
|
ruby-version: ruby
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup Ruby
|
- name: Setup Ruby
|
||||||
id: setup-ruby
|
id: setup-ruby
|
||||||
uses: ruby/setup-ruby@7372622e62b60b3cb750dcd2b9e32c247ffec26a # v1.302.0
|
uses: ruby/setup-ruby@97ecb7b512899eb71ab1bf2310a624c6f1589ac6 # v1.308.0
|
||||||
with:
|
with:
|
||||||
ruby-version: ruby
|
ruby-version: ruby
|
||||||
|
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -28,8 +28,10 @@ steps:
|
|||||||
```
|
```
|
||||||
|
|
||||||
If `version` is omitted, the action checks the repository root for `bun.lock`,
|
If `version` is omitted, the action checks the repository root for `bun.lock`,
|
||||||
`pnpm-lock.yaml`, or `package-lock.json` and uses the declared `supabase`
|
`pnpm-lock.yaml`, or `package-lock.json` and installs the declared `supabase`
|
||||||
version. If no supported lockfile is present, it falls back to `latest`.
|
package version through npm. If the lockfile includes package integrity
|
||||||
|
metadata, the action verifies it against the npm registry before installing. If
|
||||||
|
no supported lockfile is present, it falls back to `latest`.
|
||||||
|
|
||||||
A specific version of the `supabase` CLI can be installed:
|
A specific version of the `supabase` CLI can be installed:
|
||||||
|
|
||||||
@@ -47,7 +49,6 @@ steps:
|
|||||||
- uses: supabase/setup-cli@v2
|
- uses: supabase/setup-cli@v2
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
github-token: ${{ github.token }}
|
|
||||||
- run: supabase init
|
- run: supabase init
|
||||||
- run: supabase db start
|
- run: supabase db start
|
||||||
```
|
```
|
||||||
@@ -60,9 +61,9 @@ on Windows and macOS runners.
|
|||||||
The action supports the following inputs:
|
The action supports the following inputs:
|
||||||
|
|
||||||
| Name | Type | Description | Default | Required |
|
| Name | Type | Description | Default | Required |
|
||||||
| -------------- | ------ | -------------------------------------------------------------------------- | --------------------------------- | -------- |
|
| -------------- | ------ | ---------------------------------------------------------------- | --------------------------------- | -------- |
|
||||||
| `version` | String | Supabase CLI version (or `latest`) | Root lockfile version or `latest` | false |
|
| `version` | String | Supabase CLI version (or `latest`) | Root lockfile version or `latest` | false |
|
||||||
| `github-token` | String | GitHub token used to resolve `latest` without unauthenticated API limiting | | false |
|
| `github-token` | String | Deprecated; no longer used now that installs resolve through npm | | false |
|
||||||
|
|
||||||
## Advanced Usage
|
## Advanced Usage
|
||||||
|
|
||||||
|
|||||||
48
action.yml
48
action.yml
@@ -6,7 +6,7 @@ inputs:
|
|||||||
description: Version of Supabase CLI to install. If omitted, detect from the root lockfile and otherwise use latest.
|
description: Version of Supabase CLI to install. If omitted, detect from the root lockfile and otherwise use latest.
|
||||||
required: false
|
required: false
|
||||||
github-token:
|
github-token:
|
||||||
description: GitHub token used to resolve the latest Supabase CLI release without hitting unauthenticated API limits.
|
description: Deprecated. The action now installs through npm and does not use GitHub release API requests.
|
||||||
required: false
|
required: false
|
||||||
outputs:
|
outputs:
|
||||||
version:
|
version:
|
||||||
@@ -50,6 +50,51 @@ runs:
|
|||||||
|
|
||||||
echo "url=https://github.com/oven-sh/bun/releases/download/bun-v${version}/bun-linux-${arch}-musl.zip" >> "$GITHUB_OUTPUT"
|
echo "url=https://github.com/oven-sh/bun/releases/download/bun-v${version}/bun-linux-${arch}-musl.zip" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Install Alpine Runtime Dependencies
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
if [ "${RUNNER_OS}" != "Linux" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
is_musl=false
|
||||||
|
if [ -f /etc/alpine-release ]; then
|
||||||
|
is_musl=true
|
||||||
|
elif command -v ldd >/dev/null 2>&1 && ldd --version 2>&1 | grep -qi musl; then
|
||||||
|
is_musl=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${is_musl}" != "true" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Bun's musl binary and the Supabase CLI shim both dynamically link libstdc++ and libgcc.
|
||||||
|
if command -v apk >/dev/null 2>&1; then
|
||||||
|
missing_packages=""
|
||||||
|
for package in libstdc++ libgcc; do
|
||||||
|
if ! apk info -e "${package}" >/dev/null 2>&1; then
|
||||||
|
missing_packages="${missing_packages} ${package}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "${missing_packages}" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(id -u)" != "0" ]; then
|
||||||
|
echo "::error::Alpine/musl containers need${missing_packages} to run Supabase CLI. Add 'apk add --no-cache${missing_packages}' before supabase/setup-cli, or run this job container as root."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
apk add --no-cache ${missing_packages}
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "::error::Linux musl containers need libstdc++ and libgcc to run Supabase CLI. Install them before supabase/setup-cli."
|
||||||
|
exit 1
|
||||||
|
|
||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
||||||
with:
|
with:
|
||||||
@@ -67,5 +112,4 @@ runs:
|
|||||||
working-directory: ${{ github.action_path }}
|
working-directory: ${{ github.action_path }}
|
||||||
env:
|
env:
|
||||||
INPUT_VERSION: ${{ inputs.version }}
|
INPUT_VERSION: ${{ inputs.version }}
|
||||||
SUPABASE_CLI_GITHUB_TOKEN: ${{ inputs.github-token }}
|
|
||||||
run: bun src/main.ts
|
run: bun src/main.ts
|
||||||
|
|||||||
113
bun.lock
113
bun.lock
@@ -6,15 +6,14 @@
|
|||||||
"name": "setup-cli",
|
"name": "setup-cli",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^3.0.1",
|
"@actions/core": "^3.0.1",
|
||||||
"@actions/tool-cache": "^4.0.0",
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/bun": "^1.0.10",
|
"@tsconfig/bun": "^1.0.10",
|
||||||
"@types/bun": "^1.3.13",
|
"@types/bun": "^1.3.14",
|
||||||
"@typescript/native-preview": "^7.0.0-dev.20260410.1",
|
"@typescript/native-preview": "^7.0.0-dev.20260410.1",
|
||||||
"oxfmt": "^0.46.0",
|
"oxfmt": "^0.49.0",
|
||||||
"oxlint": "^1.61.0",
|
"oxlint": "^1.64.0",
|
||||||
"oxlint-tsgolint": "^0.21.1",
|
"oxlint-tsgolint": "^0.22.1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -27,99 +26,97 @@
|
|||||||
|
|
||||||
"@actions/io": ["@actions/io@3.0.2", "", {}, "sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw=="],
|
"@actions/io": ["@actions/io@3.0.2", "", {}, "sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw=="],
|
||||||
|
|
||||||
"@actions/tool-cache": ["@actions/tool-cache@4.0.0", "", { "dependencies": { "@actions/core": "^3.0.0", "@actions/exec": "^3.0.0", "@actions/http-client": "^4.0.0", "@actions/io": "^3.0.0", "semver": "^7.7.3" } }, "sha512-L8P9HbXvpvqjZDveb/fdsa55IVC0trfPgQ4ZwGo6r5af6YDVdM9vMGPZ7rgY2fAT9gGj4PSYd6bYlg3p3jD78A=="],
|
"@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.49.0", "", { "os": "android", "cpu": "arm" }, "sha512-HbifJ84prIh9+55CTPAU35JdRQrwg47y16cGerCC+iejSKOuHXYo2WDql6l7cQlzrYVtc3f4UWY+dBj2lRmOeA=="],
|
||||||
|
|
||||||
"@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.46.0", "", { "os": "android", "cpu": "arm" }, "sha512-b1doV4WRcJU+BESSlCvCjV+5CEr/T6h0frArAdV26Nir+gGNFNaylvDiiMPfF1pxeV0txZEs38ojzJaxBYg+ng=="],
|
"@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.49.0", "", { "os": "android", "cpu": "arm64" }, "sha512-Ef7SKJqAaH2d7E6eXZZa2OffIShbhFMxnGK0zd93p4qiyTJr75B0qf7lrPD+qQOwcf04BrjYJ0JUxq8d5+yZwg=="],
|
||||||
|
|
||||||
"@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.46.0", "", { "os": "android", "cpu": "arm64" }, "sha512-v6+HhjsoV3GO0u2u9jLSAZrvWfTraDxKofUIQ7/ktS7tzS+epVsxdHmeM+XxuNcAY/nWxxU1Sg4JcGTNRXraBA=="],
|
"@oxfmt/binding-darwin-arm64": ["@oxfmt/binding-darwin-arm64@0.49.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8x5DN9CsFfb432sHa9NyqX5XisGUdA53LPEGSdv/VniS+v4uEOR8Orv7A9QSB98Xxgp0t6r31DzQA/wpIobGqQ=="],
|
||||||
|
|
||||||
"@oxfmt/binding-darwin-arm64": ["@oxfmt/binding-darwin-arm64@0.46.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-3eeooJGrqGIlI5MyryDZsAcKXSmKIgAD4yYtfRrRJzXZ0UTFZtiSveIur56YPrGMYZwT4XyVhHsMqrNwr1XeFA=="],
|
"@oxfmt/binding-darwin-x64": ["@oxfmt/binding-darwin-x64@0.49.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-e0+DSVzk4ewhMVKNYDaRTmP81jNMBWR1X9al0cVKWS+hDM/dElNqD5zjTOCuLOZc4oOdp2Gx2ldrVL+yYo9TZQ=="],
|
||||||
|
|
||||||
"@oxfmt/binding-darwin-x64": ["@oxfmt/binding-darwin-x64@0.46.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-QG8BDM0CXWbu84k2SKmCqfEddPQPFiBicwtYnLqHRWZZl57HbtOLRMac/KTq2NO4AEc4ICCBpFxJIV9zcqYfkQ=="],
|
"@oxfmt/binding-freebsd-x64": ["@oxfmt/binding-freebsd-x64@0.49.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-W+mjtYtrQvFbXT/uNT+221OBhGRZ8UqNsLxjTWsjZ4GsQnRdvRC/N2NCK86BcamWr7lsTxwpwN3PULnr78sgcQ=="],
|
||||||
|
|
||||||
"@oxfmt/binding-freebsd-x64": ["@oxfmt/binding-freebsd-x64@0.46.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-9DdCqS/n2ncu/Chazvt3cpgAjAmIGQDz7hFKSrNItMApyV/Ja9mz3hD4JakIE3nS8PW9smEbPWnb389QLBY4nw=="],
|
"@oxfmt/binding-linux-arm-gnueabihf": ["@oxfmt/binding-linux-arm-gnueabihf@0.49.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Rtv6UevV7czDlLqil+NZUe4d8gs8jQo/zScSpumwyf7I+fSdLc+hc8AF3MQC7ymxSMMD9+vfiqQlsIf7wOAzXA=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-arm-gnueabihf": ["@oxfmt/binding-linux-arm-gnueabihf@0.46.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Dgs7VeE2jT0LHMhw6tPEt0xQYe54kBqHEovmWsv4FVQlegCOvlIJNx0S8n4vj8WUtpT+Z6BD2HhKJPLglLxvZg=="],
|
"@oxfmt/binding-linux-arm-musleabihf": ["@oxfmt/binding-linux-arm-musleabihf@0.49.0", "", { "os": "linux", "cpu": "arm" }, "sha512-sBi+8C/Q/MdKa5FL8ibAUCdhFBGFH7HFN/Qoyd5xQbZ/0ky3NMPpKfIBpaH0lhK2dXkGLczVQUoZ+xuNSerCdQ=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-arm-musleabihf": ["@oxfmt/binding-linux-arm-musleabihf@0.46.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Zxn3adhTH13JKnU4xXJj8FeEfF680XjXh3gSShKl57HCMBRde2tUJTgogV/1MSHA80PJEVrDa7r66TLVq3Ia7Q=="],
|
"@oxfmt/binding-linux-arm64-gnu": ["@oxfmt/binding-linux-arm64-gnu@0.49.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-JIfWenFhlzx+O8YygyZhoHFzTsdgDhxhbDRnE2iJLnnM5pWKScFvPECO2vOlA7JqJ/9S1g3uzEKuRCkHFwTjvA=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-arm64-gnu": ["@oxfmt/binding-linux-arm64-gnu@0.46.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-+TWipjrgVM8D7aIdDD0tlr3teLTTvQTn7QTE5BpT10H1Fj82gfdn9X6nn2sDgx/MepuSCfSnzFNJq2paLL0OiA=="],
|
"@oxfmt/binding-linux-arm64-musl": ["@oxfmt/binding-linux-arm64-musl@0.49.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-iNzkMPG18jPkwBOZ4/HEjwqfzAjq4RrUQ0CgId/fC1ENvYD5jLVAaU/gWgpiqP1ys07kxSsSggDd1fp3E7mQHw=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-arm64-musl": ["@oxfmt/binding-linux-arm64-musl@0.46.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-aAUPBWJ1lGwwnxZUEDLJ94+Iy6MuwJwPxUgO4sCA5mEEyDk7b+cDQ+JpX1VR150Zoyd+D49gsrUzpUK5h587Eg=="],
|
"@oxfmt/binding-linux-ppc64-gnu": ["@oxfmt/binding-linux-ppc64-gnu@0.49.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-BPHA/NN3LvoIXiid+iz3BHt5V0Rzx0tXAqRUovwE1NsbDaLG9e8mtv7evDGRIkVQacqTDBv0XL25THHsxSJosQ=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-ppc64-gnu": ["@oxfmt/binding-linux-ppc64-gnu@0.46.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ufBCJukyFX/UDrokP/r6BGDoTInnsDs7bxyzKAgMiZlt2Qu8GPJSJ6Zm6whIiJzKk0naxA8ilwmbO1LMw6Htxw=="],
|
"@oxfmt/binding-linux-riscv64-gnu": ["@oxfmt/binding-linux-riscv64-gnu@0.49.0", "", { "os": "linux", "cpu": "none" }, "sha512-3Eroshe+s69htC9JIL0+zLGQczLtRKezkMhwqQC21VC5Z/fuLvzLfbAOLgJLUq601H8gDYjy7deYycfOBjCvWg=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-riscv64-gnu": ["@oxfmt/binding-linux-riscv64-gnu@0.46.0", "", { "os": "linux", "cpu": "none" }, "sha512-eqtlC2YmPqjun76R1gVfGLuKWx7NuEnLEAudZ7n6ipSKbCZTqIKSs1b5Y8K/JHZsRpLkeSmAAjig5HOIg8fQzQ=="],
|
"@oxfmt/binding-linux-riscv64-musl": ["@oxfmt/binding-linux-riscv64-musl@0.49.0", "", { "os": "linux", "cpu": "none" }, "sha512-fnaERGgsxGm0lKAmO72EYR4BA3qBnzBTJBTi6EtUMq1D4R7EexRBMU4voXnx4TXla3SEDl9x4uNp/18SbkPjGg=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-riscv64-musl": ["@oxfmt/binding-linux-riscv64-musl@0.46.0", "", { "os": "linux", "cpu": "none" }, "sha512-yccVOO2nMXkQLGgy0He3EQEwKD7NF0zEk+/OWmroznkqXyJdN6bfK0LtNnr6/14Bh3FjpYq7bP33l/VloCnxpA=="],
|
"@oxfmt/binding-linux-s390x-gnu": ["@oxfmt/binding-linux-s390x-gnu@0.49.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-rBwasMl1Uul1MCCeTGEFKnOTL7VUxHf+634jWStrQAbzpBJgd5Yz5m4F7exVCsoI8PHn57dNjssXagXLCLB5yA=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-s390x-gnu": ["@oxfmt/binding-linux-s390x-gnu@0.46.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-aAf7fG23OQCey6VRPj9IeCraoYtpgtx0ZyJ1CXkPyT1wjzBE7c3xtuxHe/AdHaJfVVb/SXpSk8Gl1LzyQupSqw=="],
|
"@oxfmt/binding-linux-x64-gnu": ["@oxfmt/binding-linux-x64-gnu@0.49.0", "", { "os": "linux", "cpu": "x64" }, "sha512-BoC/F9xHe2y/deuBGA5Aw7bes07OD2gcL2wlpzTrfImR92vPP7S/k3LBTyspQZCNIVNdagkELcqKELwMLGIfAg=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-x64-gnu": ["@oxfmt/binding-linux-x64-gnu@0.46.0", "", { "os": "linux", "cpu": "x64" }, "sha512-q0JPsTMyJNjYrBvYFDz4WbVsafNZaPCZv4RnFypRotLqpKROtBZcEaXQW4eb9YmvLU3NckVemLJnzkSZSdmOxw=="],
|
"@oxfmt/binding-linux-x64-musl": ["@oxfmt/binding-linux-x64-musl@0.49.0", "", { "os": "linux", "cpu": "x64" }, "sha512-umY6jFADAo/oztFKl8D/S6vSrG6oBpEskcentiRuz42kZVU2kfDXMWCYavxyZR2bwPjqkHpcHZ6EZFiH3Qj9ZA=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-x64-musl": ["@oxfmt/binding-linux-x64-musl@0.46.0", "", { "os": "linux", "cpu": "x64" }, "sha512-7LsLY9Cw57GPkhSR+duI3mt9baRczK/DtHYSldQ4BEU92da9igBQNl4z7Vq5U9NNPsh1FmpKvv1q9WDtiUQR1A=="],
|
"@oxfmt/binding-openharmony-arm64": ["@oxfmt/binding-openharmony-arm64@0.49.0", "", { "os": "none", "cpu": "arm64" }, "sha512-J85zQMiw2pXiGPK+OusmDvSnJ/dgpgN7VgmB2zOBtgS8F+nsOUfSg9ZEBrwbQscjZ7tkPbm38CG4VF5f53MsiA=="],
|
||||||
|
|
||||||
"@oxfmt/binding-openharmony-arm64": ["@oxfmt/binding-openharmony-arm64@0.46.0", "", { "os": "none", "cpu": "arm64" }, "sha512-lHiBOz8Duaku7JtRNLlps3j++eOaICPZSd8FCVmTDM4DFOPT71Bjn7g6iar1z7StXlKRweUKxWUs4sA+zWGDXg=="],
|
"@oxfmt/binding-win32-arm64-msvc": ["@oxfmt/binding-win32-arm64-msvc@0.49.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-38K67XR++CoFFORDd4sMFwUVAnD6msYBdGTei+qvKGrRPO6S2PbrYPNL/eQQ1RgnnxOegNba0YQwg6uRkNcw6A=="],
|
||||||
|
|
||||||
"@oxfmt/binding-win32-arm64-msvc": ["@oxfmt/binding-win32-arm64-msvc@0.46.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-/5ktYUliP89RhgC37DBH1x20U5zPSZMy3cMEcO0j3793rbHP9MWsknBwQB6eozRzWmYrh0IFM/p20EbPvDlYlg=="],
|
"@oxfmt/binding-win32-ia32-msvc": ["@oxfmt/binding-win32-ia32-msvc@0.49.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-rXVe0HICwQF0dBgbQtBCoYf8x/SidPIdhyQl+iPuJlV7suV+qDv7yUEB3wQ4qC3nOeNxz287SwFXKzyr0kWgEg=="],
|
||||||
|
|
||||||
"@oxfmt/binding-win32-ia32-msvc": ["@oxfmt/binding-win32-ia32-msvc@0.46.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-3WTnoiuIr8XvV0DIY7SN+1uJSwKf4sPpcbHfobcRT9JutGcLaef/miyBB87jxd3aqH+mS0+G5lsgHuXLUwjjpQ=="],
|
"@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.49.0", "", { "os": "win32", "cpu": "x64" }, "sha512-gwWLwSEmBBfIK/Wh7GGd658161o4RKAvHWRaRQbJm571iQXGKfyr7UKsI1vsWvDlNLc30CxJDc8mMmCvJ/kczQ=="],
|
||||||
|
|
||||||
"@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.46.0", "", { "os": "win32", "cpu": "x64" }, "sha512-IXxiQpkYnOwNfP23vzwSfhdpxJzyiPTY7eTn6dn3DsriKddESzM8i6kfq9R7CD/PUJwCvQT22NgtygBeug3KoA=="],
|
"@oxlint-tsgolint/darwin-arm64": ["@oxlint-tsgolint/darwin-arm64@0.22.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4150Lpgc1YM09GcjA6GSrra1JoPjC7aOpfywLjWEY4vW0Sd1qKzqHF1WRaiw0/qUZ40OATYdv3aRd7ipPkWQbw=="],
|
||||||
|
|
||||||
"@oxlint-tsgolint/darwin-arm64": ["@oxlint-tsgolint/darwin-arm64@0.21.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-7TLjyWe4wG9saJc992VWmaHq2hwKfOEEVTjheReXJXaDhavMZI4X9a6nKhbEng4IVkYtzjD2jw16vw2WFXLYLw=="],
|
"@oxlint-tsgolint/darwin-x64": ["@oxlint-tsgolint/darwin-x64@0.22.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-vFWcPWYOgZs4HWcgS1EjUZg33NLcNfEYU49KGImmCfZWkflENrmBYV4HN/C0YeAPum6ZZ/goPSvQrB/cOD+NfA=="],
|
||||||
|
|
||||||
"@oxlint-tsgolint/darwin-x64": ["@oxlint-tsgolint/darwin-x64@0.21.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-7wf9Wf75nTzA7zpL9myhFe2RKvfuqGUOADNvUooCjEWvh7hmPz3lSEqTMh5Z/VQhzsG04mM9ACyghxhRzq7zFw=="],
|
"@oxlint-tsgolint/linux-arm64": ["@oxlint-tsgolint/linux-arm64@0.22.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-6LiUpP0Zir3+29FvBm7Y28q/dBjSHqTZ5MhG1Ckw4fGhI4cAvbcwXaKvbjx1TP7rRmBNOoq/M5xdpHjTb+GAew=="],
|
||||||
|
|
||||||
"@oxlint-tsgolint/linux-arm64": ["@oxlint-tsgolint/linux-arm64@0.21.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-IPuQN/Vd0Rjklg/cCGBbQyUuRBp2f6LQXpZYwk5ivOR6V/+CgiYsv8pn/PVY7gjeyoNvPQrXB7xMjHUO2YZbdw=="],
|
"@oxlint-tsgolint/linux-x64": ["@oxlint-tsgolint/linux-x64@0.22.1", "", { "os": "linux", "cpu": "x64" }, "sha512-fuX1hEQfpHauUbXADsfqVhRzrUrGabzGXbj5wsp2vKhV5uk/Rze8Mba9GdjFGECzvXudMGqHqxB4r6jGRdhxVA=="],
|
||||||
|
|
||||||
"@oxlint-tsgolint/linux-x64": ["@oxlint-tsgolint/linux-x64@0.21.1", "", { "os": "linux", "cpu": "x64" }, "sha512-d1niGuTbh2qiv7dR7tqkbOcM5cIR63of0lMBFdEQavL1KrJV8zuRdwdi68K7MNGdgoR+J5A9ajpGGvsHwp1bPg=="],
|
"@oxlint-tsgolint/win32-arm64": ["@oxlint-tsgolint/win32-arm64@0.22.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SZidAj+jrbZf9ZjBEYW0tiNZ+KasqB2zgW26qdiPpQSF/DzURnPmXz651IeA9YsmbVdHGIooEHUmev6QJdquA=="],
|
||||||
|
|
||||||
"@oxlint-tsgolint/win32-arm64": ["@oxlint-tsgolint/win32-arm64@0.21.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-ICu9y2JLnFPvFqstnWPPNqBM8LK8BWw2OTeaR0UgEMm4hOSbrZAKv1/hwZYyiLqnCNjBL87AGSQIgTHCYlsipw=="],
|
"@oxlint-tsgolint/win32-x64": ["@oxlint-tsgolint/win32-x64@0.22.1", "", { "os": "win32", "cpu": "x64" }, "sha512-QweSk9H5lFh5Y+WUf2Kq/OAN88V6+62ZwGhP38gqdRotI90luXSMkruFTj7Q2rYrzH4ZVNaSqx7NY8JpSfIzqg=="],
|
||||||
|
|
||||||
"@oxlint-tsgolint/win32-x64": ["@oxlint-tsgolint/win32-x64@0.21.1", "", { "os": "win32", "cpu": "x64" }, "sha512-cTEFCFjCj6iXfrSHcvajSPNqhEA4TxSzU3gFxbdGSAUTNXGToU99IbdhWAPSbhcucoym0XE4Zl7E41NiSkNTug=="],
|
"@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.64.0", "", { "os": "android", "cpu": "arm" }, "sha512-2r6Nq3XXGLHEXKkSj8JtmJ6N4gDw431DPFOg0ZoJHlNjnG6HVMm/ksQ10m0HJ8WBvwgMe1L50UHPaYZutCRPCw=="],
|
||||||
|
|
||||||
"@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.61.0", "", { "os": "android", "cpu": "arm" }, "sha512-6eZBPgiigK5txqoVgRqxbaxiom4lM8AP8CyKPPvpzKnQ3iFRFOIDc+0AapF+qsUSwjOzr5SGk4SxQDpQhkSJMQ=="],
|
"@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.64.0", "", { "os": "android", "cpu": "arm64" }, "sha512-ePJMpePgg7fBv+L/hVx1xXRU5/5gd5m0obLA6hPEfLXF3GjpR8idIDbY1dhQYhyz1ms2wdTccSboo6KEd2Oxtg=="],
|
||||||
|
|
||||||
"@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.61.0", "", { "os": "android", "cpu": "arm64" }, "sha512-CkwLR69MUnyv5wjzebvbbtTSUwqLxM35CXE79bHqDIK+NtKmPEUpStTcLQRZMCo4MP0qRT6TXIQVpK0ZVScnMA=="],
|
"@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.64.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-U4DMLQd10gJLuoSTLSGbfv3bGjTlUNsScm9Dgb8wwBqmCzidf1pE1pXV4doGNxqwH3KtVng1AGTINA0NvkGLvQ=="],
|
||||||
|
|
||||||
"@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.61.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8JbefTkbmvqkqWjmQrHke+MdpgT2UghhD/ktM4FOQSpGeCgbMToJEKdl9zwhr/YWTl92i4QI1KiTwVExpcUN8A=="],
|
"@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.64.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-GoRIL48QWm4/TAvjN8pB1nAG+1/uqc9EdnWT9zqHeb6wsmjZtywj8VRe5aGW47Fdb64YtLOsdLqVxOvQuz98Wg=="],
|
||||||
|
|
||||||
"@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.61.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-uWpoxDT47hTnDLcdEh5jVbso8rlTTu5o0zuqa9J8E0JAKmIWn7kGFEIB03Pycn2hd2vKxybPGLhjURy/9We5FQ=="],
|
"@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.64.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-5dFkv4tkg7PxJJGS9/OjrJwjhuHczrd3OQOkRE0wHcLM+ncUnULtzEPWjqGOxTXxZnLWcB91bGiIznx89TVXyQ=="],
|
||||||
|
|
||||||
"@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.61.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-K/o4hEyW7flfMel0iBVznmMBt7VIMHGdjADocHKpK1DUF9erpWnJ+BSSWd2W0c8K3mPtpph+CuHzRU6CI3l9jQ=="],
|
"@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.64.0", "", { "os": "linux", "cpu": "arm" }, "sha512-jsBqMLl/uOL5+Kq/+BtK9FrmiNGUbx8SiyZXv+WlUxA45KuwcLu9BfiSIL3I3DBDgWM3yZizDITnTK9BcqNBQg=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.61.0", "", { "os": "linux", "cpu": "arm" }, "sha512-P6040ZkcyweJ0Po9yEFqJCdvZnf3VNCGs1SIHgXDf8AAQNC6ID/heXQs9iSgo2FH7gKaKq32VWc59XZwL34C5Q=="],
|
"@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.64.0", "", { "os": "linux", "cpu": "arm" }, "sha512-1lrj8At/Uuc9GhjrVFBQo0NEjfBrTkzpmtHIGAhNnIXqn1CAyGL+qrztUsXb2GIluJrpl9Q7qRLJOb/NqydacQ=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.61.0", "", { "os": "linux", "cpu": "arm" }, "sha512-bwxrGCzTZkuB+THv2TQ1aTkVEfv5oz8sl+0XZZCpoYzErJD8OhPQOTA0ENPd1zJz8QsVdSzSrS2umKtPq4/JXg=="],
|
"@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.64.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-HpSQbubwh03mMhAdy2BYtad/fsY8vDFHDAb6bUwuCYg2VD3xCQgn6ArKcO0oZyLCheacKTv4PrF3Mfu5hgoE2g=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.61.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-vkhb9/wKguMkLlrm3FoJW/Xmdv31GgYAE+x8lxxQ+7HeOxXUySI0q36a3NTVIuQUdLzxCI1zzMGsk1o37FOe3w=="],
|
"@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.64.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-00QQ0h0Y7u0G69BgiH3+ky2aaq/QvkDL6DYok8htIuJHxybiux5aQ8jwmg8qIk9wha6UagUP2BAwAzbemcJbpg=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.61.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-bl1dQh8LnVqsj6oOQAcxwbuOmNJkwc4p6o//HTBZhNTzJy21TLDwAviMqUFNUxDHkPGpmdKTSN4tWTjLryP8xg=="],
|
"@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.64.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-2GaimTV6EMW+s5HS0An3oGbQme3BgHswvfVdGk3EB57Xe9+/gyT+Qd7lNVzb3rtir52vbIPzXfaYArzs5b5zcw=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.61.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-QoOX6KB2IiEpyOj/HKqaxi+NQHPnOgNgnr22n9N4ANJCzXkUlj1UmeAbFb4PpqdlHIzvGDM5xZ0OKtcLq9RhiQ=="],
|
"@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.64.0", "", { "os": "linux", "cpu": "none" }, "sha512-H46AtFb9wypjoVwGdlxrm0DsD809NGmtiK9HiyPKTxkSte2YjhC4S+00rOIrwCaxcyPiGid3Y3OMXp5KMAkGZw=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.61.0", "", { "os": "linux", "cpu": "none" }, "sha512-1TGcTerjY6p152wCof3oKElccq3xHljS/Mucp04gV/4ATpP6nO7YNnp7opEg6SHkv2a57/b4b8Ndm9znJ1/qAw=="],
|
"@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.64.0", "", { "os": "linux", "cpu": "none" }, "sha512-HEgsidjjvvyzdg82icYkuFCf7REDV7B9JFwbIMbVwrKLBY0MrXX+bku3POn/hduZ2yW91IyVDUMq0Bf02KwXQw=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.61.0", "", { "os": "linux", "cpu": "none" }, "sha512-65wXEmZIrX2ADwC8i/qFL4EWLSbeuBpAm3suuX1vu4IQkKd+wLT/HU/BOl84kp91u2SxPkPDyQgu4yrqp8vwVA=="],
|
"@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.64.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-Axvm8qryotmKN00P5w4JapaSjvP2LOSbdbBJiX+2SuHd3QzhW7TUc8skqgw+ahQZ5DmzEYeHCqauvW8f32Ns6Q=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.61.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-TVvhgMvor7Qa6COeXxCJ7ENOM+lcAOGsQ0iUdPSCv2hxb9qSHLQ4XF1h50S6RE1gBOJ0WV3rNukg4JJJP1LWRA=="],
|
"@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.64.0", "", { "os": "linux", "cpu": "x64" }, "sha512-cR60vSd7+m+KRZ3GQGfDxWwahW5RMXg0qlGvAluZr0fTUYvw0H9N9AXAF/M/PMqgytyqvVNmBAkJG9l7U30Y1g=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.61.0", "", { "os": "linux", "cpu": "x64" }, "sha512-SjpS5uYuFoDnDdZPwZE59ndF95AsY47R5MliuneTWR1pDm2CxGJaYXbKULI71t5TVfLQUWmrHEGRL9xvuq6dnA=="],
|
"@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.64.0", "", { "os": "linux", "cpu": "x64" }, "sha512-2u/aPZ9pEg7HnvZPDsHxUGNnrpr4qaHi+mCgLgpt+LYRzPrS4Px4wPfkIdRdr2GvKnaYyt+XSlto0Vm5sbStTg=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.61.0", "", { "os": "linux", "cpu": "x64" }, "sha512-gGfAeGD4sNJGILZbc/yKcIimO9wQnPMoYp9swAaKeEtwsSQAbU+rsdQze5SBtIP6j0QDzeYd4XSSUCRCF+LIeQ=="],
|
"@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.64.0", "", { "os": "none", "cpu": "arm64" }, "sha512-kfhkGfCdoXLSxEkrhDlJrvBYajGmq+ma4EMc53dsOWTq+rIBOlI0vTBmpZNnM5oH2LY/K/w1HAK+UQEgjgpVUg=="],
|
||||||
|
|
||||||
"@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.61.0", "", { "os": "none", "cpu": "arm64" }, "sha512-OlVT0LrG/ct33EVtWRyR+B/othwmDWeRxfi13wUdPeb3lAT5TgTcFDcfLfarZtzB4W1nWF/zICMgYdkggX2WmQ=="],
|
"@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.64.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-r/cNKBFieONoVu2bb1KkVouq9W+edDUgHumXJGphCRRj+U0xaD4nanrw8ZOqo0IsutPkEM4vCcGBpak6x5aXMg=="],
|
||||||
|
|
||||||
"@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.61.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-vI//NZPJk6DToiovPtaiwD4iQ7kO1r5ReWQD0sOOyKRtP3E2f6jxin4uvwi3OvDzHA2EFfd7DcZl5dtkQh7g1w=="],
|
"@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.64.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-tUw0xUUwEFVZbpJoeCblkv8SJA4Xz3CdXCJbAnBsiNLyxDrk2tLcxEAS6M73Q7hHHDg3OtwI8vZVK3t5RJt4Gw=="],
|
||||||
|
|
||||||
"@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.61.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-0ySj4/4zd2XjePs3XAQq7IigIstN4LPQZgCyigX5/ERMLjdWAJfnxcTsrtxZxuij8guJW8foXuHmhGxW0H4dDA=="],
|
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.64.0", "", { "os": "win32", "cpu": "x64" }, "sha512-9CBR+LO0JVST87fNTzzNxS5I29jIUO5gxT9i9+M3SDHHALElj9sY1Prf12tad3vIRC6OD7Ehtvvh+sn13vSwHw=="],
|
||||||
|
|
||||||
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.61.0", "", { "os": "win32", "cpu": "x64" }, "sha512-0xgSiyeqDLDZxXoe9CVJrOx3TUVsfyoOY7cNi03JbItNcC9WCZqrSNdrAbHONxhSPaVh/lzfnDcON1RqSUMhHw=="],
|
|
||||||
|
|
||||||
"@tsconfig/bun": ["@tsconfig/bun@1.0.10", "", {}, "sha512-5AV5YknQjNyoYzZ/8NG0dawqew/wH+x7ANiCfCIn29qo0cdbd1EryvFD1k5NSZWLBMOI/fGqMIaxi58GPIP9Cg=="],
|
"@tsconfig/bun": ["@tsconfig/bun@1.0.10", "", {}, "sha512-5AV5YknQjNyoYzZ/8NG0dawqew/wH+x7ANiCfCIn29qo0cdbd1EryvFD1k5NSZWLBMOI/fGqMIaxi58GPIP9Cg=="],
|
||||||
|
|
||||||
"@types/bun": ["@types/bun@1.3.13", "", { "dependencies": { "bun-types": "1.3.13" } }, "sha512-9fqXWk5YIHGGnUau9TEi+qdlTYDAnOj+xLCmSTwXfAIqXr2x4tytJb43E9uCvt09zJURKXwAtkoH4nLQfzeTXw=="],
|
"@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@20.19.37", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw=="],
|
"@types/node": ["@types/node@20.19.37", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw=="],
|
||||||
|
|
||||||
@@ -139,15 +136,13 @@
|
|||||||
|
|
||||||
"@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260410.1", "", { "os": "win32", "cpu": "x64" }, "sha512-dMFT4tdHBe2vVA2WPQMjorT+fzCURRtillevQzz8/bwCEz2uXSnpu4oLRLS5045ppGE0wCFELE+Hq5z2oRddDw=="],
|
"@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260410.1", "", { "os": "win32", "cpu": "x64" }, "sha512-dMFT4tdHBe2vVA2WPQMjorT+fzCURRtillevQzz8/bwCEz2uXSnpu4oLRLS5045ppGE0wCFELE+Hq5z2oRddDw=="],
|
||||||
|
|
||||||
"bun-types": ["bun-types@1.3.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-QXKeHLlOLqQX9LgYaHJfzdBaV21T63HhFJnvuRCcjZiaUDpbs5ED1MgxbMra71CsryN/1dAoXuJJJwIv/2drVA=="],
|
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
|
||||||
|
|
||||||
"oxfmt": ["oxfmt@0.46.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.46.0", "@oxfmt/binding-android-arm64": "0.46.0", "@oxfmt/binding-darwin-arm64": "0.46.0", "@oxfmt/binding-darwin-x64": "0.46.0", "@oxfmt/binding-freebsd-x64": "0.46.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.46.0", "@oxfmt/binding-linux-arm-musleabihf": "0.46.0", "@oxfmt/binding-linux-arm64-gnu": "0.46.0", "@oxfmt/binding-linux-arm64-musl": "0.46.0", "@oxfmt/binding-linux-ppc64-gnu": "0.46.0", "@oxfmt/binding-linux-riscv64-gnu": "0.46.0", "@oxfmt/binding-linux-riscv64-musl": "0.46.0", "@oxfmt/binding-linux-s390x-gnu": "0.46.0", "@oxfmt/binding-linux-x64-gnu": "0.46.0", "@oxfmt/binding-linux-x64-musl": "0.46.0", "@oxfmt/binding-openharmony-arm64": "0.46.0", "@oxfmt/binding-win32-arm64-msvc": "0.46.0", "@oxfmt/binding-win32-ia32-msvc": "0.46.0", "@oxfmt/binding-win32-x64-msvc": "0.46.0" }, "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-CopwJOwPAjZ9p76fCvz+mSOJTw9/NY3cSksZK3VO/bUQ8UoEcketNgUuYS0UB3p+R9XnXe7wGGXUmyFxc7QxJA=="],
|
"oxfmt": ["oxfmt@0.49.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.49.0", "@oxfmt/binding-android-arm64": "0.49.0", "@oxfmt/binding-darwin-arm64": "0.49.0", "@oxfmt/binding-darwin-x64": "0.49.0", "@oxfmt/binding-freebsd-x64": "0.49.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.49.0", "@oxfmt/binding-linux-arm-musleabihf": "0.49.0", "@oxfmt/binding-linux-arm64-gnu": "0.49.0", "@oxfmt/binding-linux-arm64-musl": "0.49.0", "@oxfmt/binding-linux-ppc64-gnu": "0.49.0", "@oxfmt/binding-linux-riscv64-gnu": "0.49.0", "@oxfmt/binding-linux-riscv64-musl": "0.49.0", "@oxfmt/binding-linux-s390x-gnu": "0.49.0", "@oxfmt/binding-linux-x64-gnu": "0.49.0", "@oxfmt/binding-linux-x64-musl": "0.49.0", "@oxfmt/binding-openharmony-arm64": "0.49.0", "@oxfmt/binding-win32-arm64-msvc": "0.49.0", "@oxfmt/binding-win32-ia32-msvc": "0.49.0", "@oxfmt/binding-win32-x64-msvc": "0.49.0" }, "peerDependencies": { "svelte": "^5.0.0" }, "optionalPeers": ["svelte"], "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-IAHFMdlJSWe+oAr65dx22UvjCtV9DBMisAuLnKpDqMQrctzCkGnj3QRwNHm0d+uwSWPalsDF8ZYLz9rh6nH2IQ=="],
|
||||||
|
|
||||||
"oxlint": ["oxlint@1.61.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.61.0", "@oxlint/binding-android-arm64": "1.61.0", "@oxlint/binding-darwin-arm64": "1.61.0", "@oxlint/binding-darwin-x64": "1.61.0", "@oxlint/binding-freebsd-x64": "1.61.0", "@oxlint/binding-linux-arm-gnueabihf": "1.61.0", "@oxlint/binding-linux-arm-musleabihf": "1.61.0", "@oxlint/binding-linux-arm64-gnu": "1.61.0", "@oxlint/binding-linux-arm64-musl": "1.61.0", "@oxlint/binding-linux-ppc64-gnu": "1.61.0", "@oxlint/binding-linux-riscv64-gnu": "1.61.0", "@oxlint/binding-linux-riscv64-musl": "1.61.0", "@oxlint/binding-linux-s390x-gnu": "1.61.0", "@oxlint/binding-linux-x64-gnu": "1.61.0", "@oxlint/binding-linux-x64-musl": "1.61.0", "@oxlint/binding-openharmony-arm64": "1.61.0", "@oxlint/binding-win32-arm64-msvc": "1.61.0", "@oxlint/binding-win32-ia32-msvc": "1.61.0", "@oxlint/binding-win32-x64-msvc": "1.61.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.18.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-ZC0ALuhDZ6ivOFG+sy0D0pEDN49EvsId98zVlmYdkcXHsEM14m/qTNUEsUpiFiCVbpIxYtVBmmLE87nsbUHohQ=="],
|
"oxlint": ["oxlint@1.64.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.64.0", "@oxlint/binding-android-arm64": "1.64.0", "@oxlint/binding-darwin-arm64": "1.64.0", "@oxlint/binding-darwin-x64": "1.64.0", "@oxlint/binding-freebsd-x64": "1.64.0", "@oxlint/binding-linux-arm-gnueabihf": "1.64.0", "@oxlint/binding-linux-arm-musleabihf": "1.64.0", "@oxlint/binding-linux-arm64-gnu": "1.64.0", "@oxlint/binding-linux-arm64-musl": "1.64.0", "@oxlint/binding-linux-ppc64-gnu": "1.64.0", "@oxlint/binding-linux-riscv64-gnu": "1.64.0", "@oxlint/binding-linux-riscv64-musl": "1.64.0", "@oxlint/binding-linux-s390x-gnu": "1.64.0", "@oxlint/binding-linux-x64-gnu": "1.64.0", "@oxlint/binding-linux-x64-musl": "1.64.0", "@oxlint/binding-openharmony-arm64": "1.64.0", "@oxlint/binding-win32-arm64-msvc": "1.64.0", "@oxlint/binding-win32-ia32-msvc": "1.64.0", "@oxlint/binding-win32-x64-msvc": "1.64.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.22.1" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-Star3SNpWPeWFPw7kRXIhXUSn6fdiAl25q15CQzH/9WaOtG6e9CWTc25vNZOCr4PE1yEP1GtKJKIKglhj3OmEQ=="],
|
||||||
|
|
||||||
"oxlint-tsgolint": ["oxlint-tsgolint@0.21.1", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "0.21.1", "@oxlint-tsgolint/darwin-x64": "0.21.1", "@oxlint-tsgolint/linux-arm64": "0.21.1", "@oxlint-tsgolint/linux-x64": "0.21.1", "@oxlint-tsgolint/win32-arm64": "0.21.1", "@oxlint-tsgolint/win32-x64": "0.21.1" }, "bin": { "tsgolint": "bin/tsgolint.js" } }, "sha512-O2hxiT14C2HJkwzBU6CQBFPoagSd/IcV+Tt3e3UUaXFwbW4BO5DSDPSSboc3UM5MIDY+MLyepvtQwBQafNxWdw=="],
|
"oxlint-tsgolint": ["oxlint-tsgolint@0.22.1", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "0.22.1", "@oxlint-tsgolint/darwin-x64": "0.22.1", "@oxlint-tsgolint/linux-arm64": "0.22.1", "@oxlint-tsgolint/linux-x64": "0.22.1", "@oxlint-tsgolint/win32-arm64": "0.22.1", "@oxlint-tsgolint/win32-x64": "0.22.1" }, "bin": { "tsgolint": "bin/tsgolint.js" } }, "sha512-YUSGSLUnoolsu8gxISEDio3q1rtsCozwfOzASUn3DT2mR2EeQ93uEEnen7s+6LpF+lyTQFln1pQfqwBh/fsVEg=="],
|
||||||
|
|
||||||
"semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
|
||||||
|
|
||||||
"tinypool": ["tinypool@2.1.0", "", {}, "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw=="],
|
"tinypool": ["tinypool@2.1.0", "", {}, "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw=="],
|
||||||
|
|
||||||
@@ -156,7 +151,5 @@
|
|||||||
"undici": ["undici@6.24.1", "", {}, "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA=="],
|
"undici": ["undici@6.24.1", "", {}, "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA=="],
|
||||||
|
|
||||||
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||||
|
|
||||||
"@actions/tool-cache/@actions/core": ["@actions/core@3.0.0", "", { "dependencies": { "@actions/exec": "^3.0.0", "@actions/http-client": "^4.0.0" } }, "sha512-zYt6cz+ivnTmiT/ksRVriMBOiuoUpDCJJlZ5KPl2/FRdvwU3f7MPh9qftvbkXJThragzUZieit2nyHUyw53Seg=="],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
package.json
11
package.json
@@ -24,16 +24,15 @@
|
|||||||
"typecheck": "bun x tsgo -p tsconfig.json --noEmit"
|
"typecheck": "bun x tsgo -p tsconfig.json --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^3.0.1",
|
"@actions/core": "^3.0.1"
|
||||||
"@actions/tool-cache": "^4.0.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/bun": "^1.0.10",
|
"@tsconfig/bun": "^1.0.10",
|
||||||
"@types/bun": "^1.3.13",
|
"@types/bun": "^1.3.14",
|
||||||
"@typescript/native-preview": "^7.0.0-dev.20260410.1",
|
"@typescript/native-preview": "^7.0.0-dev.20260410.1",
|
||||||
"oxfmt": "^0.46.0",
|
"oxfmt": "^0.49.0",
|
||||||
"oxlint": "^1.61.0",
|
"oxlint": "^1.64.0",
|
||||||
"oxlint-tsgolint": "^0.21.1"
|
"oxlint-tsgolint": "^0.22.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.3.10"
|
"bun": ">=1.3.10"
|
||||||
|
|||||||
577
src/main.test.ts
577
src/main.test.ts
@@ -1,30 +1,26 @@
|
|||||||
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import process from "node:process";
|
import process from "node:process";
|
||||||
import { fileURLToPath } from "node:url";
|
|
||||||
import { afterEach, expect, mock, spyOn, test } from "bun:test";
|
import { afterEach, expect, mock, spyOn, test } from "bun:test";
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import * as tc from "@actions/tool-cache";
|
|
||||||
|
|
||||||
const repo = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
||||||
const defaultEntrypoint = fileURLToPath(new URL("./main.ts", import.meta.url));
|
|
||||||
const CLI_CONFIG_REGISTRY = "SUPABASE_INTERNAL_IMAGE_REGISTRY";
|
const CLI_CONFIG_REGISTRY = "SUPABASE_INTERNAL_IMAGE_REGISTRY";
|
||||||
const GITHUB_RELEASES_API = "https://api.github.com/repos/supabase/cli/releases/latest";
|
const originalPath = process.env.PATH;
|
||||||
const GITHUB_TOKEN_ENV = "SUPABASE_CLI_GITHUB_TOKEN";
|
const originalRunnerTemp = process.env.RUNNER_TEMP;
|
||||||
const originalWorkspace = process.env.GITHUB_WORKSPACE;
|
const originalWorkspace = process.env.GITHUB_WORKSPACE;
|
||||||
const originalGithubToken = process.env[GITHUB_TOKEN_ENV];
|
|
||||||
const tempDirs = new Set<string>();
|
const tempDirs = new Set<string>();
|
||||||
let mainModule: typeof import("./main.ts") | null = null;
|
let mainModule: typeof import("./main.ts") | null = null;
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
mock.restore();
|
mock.restore();
|
||||||
|
process.env.PATH = originalPath;
|
||||||
|
process.env.RUNNER_TEMP = originalRunnerTemp;
|
||||||
process.env.GITHUB_WORKSPACE = originalWorkspace;
|
process.env.GITHUB_WORKSPACE = originalWorkspace;
|
||||||
if (originalGithubToken === undefined) {
|
delete process.env.FAKE_CLI_VERSION;
|
||||||
delete process.env[GITHUB_TOKEN_ENV];
|
delete process.env.FAKE_NPM_INTEGRITY;
|
||||||
} else {
|
delete process.env.FAKE_NPM_LOG;
|
||||||
process.env[GITHUB_TOKEN_ENV] = originalGithubToken;
|
delete process.env.SUPABASE_SETUP_CLI_NPM;
|
||||||
}
|
|
||||||
|
|
||||||
for (const dir of tempDirs) {
|
for (const dir of tempDirs) {
|
||||||
rmSync(dir, { force: true, recursive: true });
|
rmSync(dir, { force: true, recursive: true });
|
||||||
@@ -32,32 +28,14 @@ afterEach(() => {
|
|||||||
tempDirs.clear();
|
tempDirs.clear();
|
||||||
});
|
});
|
||||||
|
|
||||||
function createFakeCli(versionOutput: string): string {
|
function createTempDir(prefix: string): string {
|
||||||
const dir = mkdtempSync(path.join(os.tmpdir(), "setup-cli-"));
|
const dir = mkdtempSync(path.join(os.tmpdir(), prefix));
|
||||||
tempDirs.add(dir);
|
tempDirs.add(dir);
|
||||||
|
|
||||||
if (process.platform === "win32") {
|
|
||||||
writeFileSync(
|
|
||||||
path.join(dir, "supabase.cmd"),
|
|
||||||
versionOutput ? `@echo off\r\necho ${versionOutput}\r\n` : "@echo off\r\n",
|
|
||||||
);
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
const escapedOutput = versionOutput.replaceAll("'", "'\"'\"'");
|
|
||||||
writeFileSync(
|
|
||||||
path.join(dir, "supabase"),
|
|
||||||
versionOutput
|
|
||||||
? `#!/usr/bin/env bash\nprintf '%s\\n' '${escapedOutput}'\n`
|
|
||||||
: "#!/usr/bin/env bash\n",
|
|
||||||
);
|
|
||||||
Bun.spawnSync(["chmod", "+x", path.join(dir, "supabase")]);
|
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createWorkspace(files: Record<string, string>): string {
|
function createWorkspace(files: Record<string, string>): string {
|
||||||
const dir = mkdtempSync(path.join(os.tmpdir(), "setup-cli-workspace-"));
|
const dir = createTempDir("setup-cli-workspace-");
|
||||||
tempDirs.add(dir);
|
|
||||||
|
|
||||||
for (const [relativePath, content] of Object.entries(files)) {
|
for (const [relativePath, content] of Object.entries(files)) {
|
||||||
const filePath = path.join(dir, relativePath);
|
const filePath = path.join(dir, relativePath);
|
||||||
@@ -73,6 +51,7 @@ function createBunLock(
|
|||||||
options: {
|
options: {
|
||||||
includeDependency?: boolean;
|
includeDependency?: boolean;
|
||||||
includePackageEntry?: boolean;
|
includePackageEntry?: boolean;
|
||||||
|
integrity?: string;
|
||||||
useDevDependency?: boolean;
|
useDevDependency?: boolean;
|
||||||
} = {},
|
} = {},
|
||||||
): string {
|
): string {
|
||||||
@@ -98,7 +77,7 @@ ${
|
|||||||
"supabase@${version}",
|
"supabase@${version}",
|
||||||
"",
|
"",
|
||||||
{},
|
{},
|
||||||
"sha512-test"
|
"${options.integrity ?? "sha512-bun"}"
|
||||||
]`
|
]`
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
@@ -109,7 +88,12 @@ ${
|
|||||||
|
|
||||||
function createPnpmLock(
|
function createPnpmLock(
|
||||||
version: string,
|
version: string,
|
||||||
options: { asString?: boolean; includeVersion?: boolean; useDevDependency?: boolean } = {},
|
options: {
|
||||||
|
asString?: boolean;
|
||||||
|
includeVersion?: boolean;
|
||||||
|
integrity?: string;
|
||||||
|
useDevDependency?: boolean;
|
||||||
|
} = {},
|
||||||
): string {
|
): string {
|
||||||
const dependencyKey = options.useDevDependency ? "devDependencies" : "dependencies";
|
const dependencyKey = options.useDevDependency ? "devDependencies" : "dependencies";
|
||||||
|
|
||||||
@@ -127,11 +111,11 @@ ${options.includeVersion === false ? "" : ` version: ${version}`}`
|
|||||||
packages:
|
packages:
|
||||||
supabase@${version}:
|
supabase@${version}:
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-test
|
integrity: ${options.integrity ?? "sha512-pnpm"}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPackageLock(version: string): string {
|
function createPackageLock(version: string, integrity = "sha512-package-lock"): string {
|
||||||
return JSON.stringify(
|
return JSON.stringify(
|
||||||
{
|
{
|
||||||
name: "app",
|
name: "app",
|
||||||
@@ -143,6 +127,7 @@ function createPackageLock(version: string): string {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"node_modules/supabase": {
|
"node_modules/supabase": {
|
||||||
|
integrity,
|
||||||
version,
|
version,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -152,29 +137,105 @@ function createPackageLock(version: string): string {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createActionSpies(inputVersion: string, cliDir: string, expectedUrlFragment: string) {
|
function createFakeNpm(): string {
|
||||||
return {
|
const root = createTempDir("setup-cli-fake-npm-");
|
||||||
getInput: spyOn(core, "getInput").mockReturnValue(inputVersion),
|
const binDir = path.join(root, "bin");
|
||||||
setOutput: spyOn(core, "setOutput").mockImplementation(() => {}),
|
const scriptPath = path.join(root, "fake-npm.js");
|
||||||
addPath: spyOn(core, "addPath").mockImplementation(() => {}),
|
mkdirSync(binDir, { recursive: true });
|
||||||
exportVariable: spyOn(core, "exportVariable").mockImplementation(() => {}),
|
writeFileSync(
|
||||||
setFailed: spyOn(core, "setFailed").mockImplementation(() => {}),
|
scriptPath,
|
||||||
downloadTool: spyOn(tc, "downloadTool").mockImplementation(async (url: string) => {
|
`import { appendFileSync, mkdirSync, writeFileSync } from "node:fs";
|
||||||
expect(url).toContain(expectedUrlFragment);
|
import path from "node:path";
|
||||||
return path.join(os.tmpdir(), "supabase-cli.tar.gz");
|
|
||||||
}),
|
const args = process.argv.slice(2);
|
||||||
extractTar: spyOn(tc, "extractTar").mockImplementation(async () => cliDir),
|
appendFileSync(process.env.FAKE_NPM_LOG, JSON.stringify(args) + "\\n");
|
||||||
extractZip: spyOn(tc, "extractZip").mockImplementation(async () => cliDir),
|
|
||||||
};
|
if (args[0] === "view") {
|
||||||
|
console.log(JSON.stringify(process.env.FAKE_NPM_INTEGRITY ?? "sha512-test"));
|
||||||
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mockLatestRelease(version = "v2.99.0") {
|
if (args[0] !== "install") {
|
||||||
return spyOn(globalThis, "fetch").mockResolvedValue(
|
console.error("Unexpected npm command: " + args.join(" "));
|
||||||
new Response(JSON.stringify({ tag_name: version }), {
|
process.exit(1);
|
||||||
status: 200,
|
}
|
||||||
statusText: "OK",
|
|
||||||
}),
|
const prefixIndex = args.indexOf("--prefix");
|
||||||
|
const prefix = prefixIndex === -1 ? undefined : args[prefixIndex + 1];
|
||||||
|
if (!prefix) {
|
||||||
|
console.error("Missing --prefix");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const binDir = path.join(prefix, "node_modules", ".bin");
|
||||||
|
mkdirSync(binDir, { recursive: true });
|
||||||
|
|
||||||
|
if (process.platform === "win32") {
|
||||||
|
writeFileSync(
|
||||||
|
path.join(binDir, "supabase.cmd"),
|
||||||
|
process.env.FAKE_CLI_VERSION ? "@echo off\\r\\necho " + process.env.FAKE_CLI_VERSION + "\\r\\n" : "@echo off\\r\\n",
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
writeFileSync(
|
||||||
|
path.join(binDir, "supabase"),
|
||||||
|
process.env.FAKE_CLI_VERSION
|
||||||
|
? "#!/usr/bin/env bash\\nprintf '%s\\\\n' '" + process.env.FAKE_CLI_VERSION.replaceAll("'", "'\\\\''") + "'\\n"
|
||||||
|
: "#!/usr/bin/env bash\\n",
|
||||||
|
{ mode: 0o755 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (process.platform === "win32") {
|
||||||
|
writeFileSync(
|
||||||
|
path.join(binDir, "npm.cmd"),
|
||||||
|
`@echo off\r\n"${process.execPath}" "${scriptPath}" %*\r\n`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
writeFileSync(
|
||||||
|
path.join(binDir, "npm"),
|
||||||
|
`#!/usr/bin/env bash\nexec "${process.execPath}" "${scriptPath}" "$@"\n`,
|
||||||
|
{ mode: 0o755 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return binDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
function installFakeNpm(versionOutput = "supabase 2.101.0", integrity = "sha512-test"): string {
|
||||||
|
const binDir = createFakeNpm();
|
||||||
|
const logPath = path.join(createTempDir("setup-cli-fake-npm-log-"), "npm.log");
|
||||||
|
writeFileSync(logPath, "");
|
||||||
|
process.env.FAKE_CLI_VERSION = versionOutput;
|
||||||
|
process.env.FAKE_NPM_INTEGRITY = integrity;
|
||||||
|
process.env.FAKE_NPM_LOG = logPath;
|
||||||
|
process.env.PATH = `${binDir}${path.delimiter}${originalPath ?? ""}`;
|
||||||
|
process.env.RUNNER_TEMP = createTempDir("setup-cli-runner-temp-");
|
||||||
|
process.env.SUPABASE_SETUP_CLI_NPM = path.join(
|
||||||
|
binDir,
|
||||||
|
process.platform === "win32" ? "npm.cmd" : "npm",
|
||||||
|
);
|
||||||
|
|
||||||
|
return logPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readNpmCalls(logPath: string): string[][] {
|
||||||
|
return readFileSync(logPath, "utf8")
|
||||||
|
.trim()
|
||||||
|
.split("\n")
|
||||||
|
.filter(Boolean)
|
||||||
|
.map((line) => JSON.parse(line) as string[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createActionSpies(inputVersion: string) {
|
||||||
|
return {
|
||||||
|
addPath: spyOn(core, "addPath").mockImplementation(() => {}),
|
||||||
|
exportVariable: spyOn(core, "exportVariable").mockImplementation(() => {}),
|
||||||
|
getInput: spyOn(core, "getInput").mockReturnValue(inputVersion),
|
||||||
|
setFailed: spyOn(core, "setFailed").mockImplementation(() => {}),
|
||||||
|
setOutput: spyOn(core, "setOutput").mockImplementation(() => {}),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getMainModule(): Promise<typeof import("./main.ts")> {
|
async function getMainModule(): Promise<typeof import("./main.ts")> {
|
||||||
@@ -185,193 +246,52 @@ async function getMainModule(): Promise<typeof import("./main.ts")> {
|
|||||||
return mainModule;
|
return mainModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
test("uses versioned tar archives for Supabase CLI v2.99.0 and later", async () => {
|
test("uses an explicit npm package version when provided", async () => {
|
||||||
const { getDownloadArchive } = await getMainModule();
|
const { resolvePackage } = await getMainModule();
|
||||||
|
|
||||||
const archive = await getDownloadArchive("2.99.0", "linux", "x64");
|
expect(resolvePackage("v2.101.0")).toEqual({
|
||||||
|
spec: "supabase@2.101.0",
|
||||||
expect(archive).toEqual({
|
version: "2.101.0",
|
||||||
url: "https://github.com/supabase/cli/releases/download/v2.99.0/supabase_2.99.0_linux_amd64.tar.gz",
|
|
||||||
format: "tar",
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("uses apk archives for Supabase CLI v2.99.0 and later on Linux musl", async () => {
|
test("uses the root bun.lock resolution when version is omitted", async () => {
|
||||||
const { getDownloadArchive } = await getMainModule();
|
|
||||||
|
|
||||||
const archive = await getDownloadArchive("2.100.1", "linux", "x64", true);
|
|
||||||
|
|
||||||
expect(archive).toEqual({
|
|
||||||
url: "https://github.com/supabase/cli/releases/download/v2.100.1/supabase_2.100.1_linux_amd64.apk",
|
|
||||||
format: "apk",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("keeps tar archives before Supabase CLI v2.99.0 on Linux musl", async () => {
|
|
||||||
const { getDownloadArchive } = await getMainModule();
|
|
||||||
|
|
||||||
const archive = await getDownloadArchive("2.98.2", "linux", "x64", true);
|
|
||||||
|
|
||||||
expect(archive).toEqual({
|
|
||||||
url: "https://github.com/supabase/cli/releases/download/v2.98.2/supabase_linux_amd64.tar.gz",
|
|
||||||
format: "tar",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("uses usr/bin as the CLI path for apk archives", async () => {
|
|
||||||
const { getCliPath } = await getMainModule();
|
|
||||||
|
|
||||||
expect(getCliPath("/tmp/extracted", "apk")).toBe(path.join("/tmp/extracted", "usr", "bin"));
|
|
||||||
expect(getCliPath("/tmp/extracted", "tar")).toBe("/tmp/extracted");
|
|
||||||
expect(getCliPath("/tmp/extracted", "zip")).toBe("/tmp/extracted");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("keeps the unversioned tar archive layout before Supabase CLI v2.99.0", async () => {
|
|
||||||
const { getDownloadArchive } = await getMainModule();
|
|
||||||
|
|
||||||
const archive = await getDownloadArchive("2.98.2", "linux", "x64");
|
|
||||||
|
|
||||||
expect(archive).toEqual({
|
|
||||||
url: "https://github.com/supabase/cli/releases/download/v2.98.2/supabase_linux_amd64.tar.gz",
|
|
||||||
format: "tar",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("uses versioned zip archives for Windows Supabase CLI v2.99.0 and later", async () => {
|
|
||||||
const { getDownloadArchive } = await getMainModule();
|
|
||||||
|
|
||||||
const archive = await getDownloadArchive("2.99.0", "win32", "x64");
|
|
||||||
|
|
||||||
expect(archive).toEqual({
|
|
||||||
url: "https://github.com/supabase/cli/releases/download/v2.99.0/supabase_2.99.0_windows_amd64.zip",
|
|
||||||
format: "zip",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("resolves latest before choosing a versioned Supabase CLI archive", async () => {
|
|
||||||
mockLatestRelease("v2.99.0");
|
|
||||||
const { getDownloadArchive } = await getMainModule();
|
|
||||||
|
|
||||||
const archive = await getDownloadArchive("latest", "darwin", "arm64");
|
|
||||||
|
|
||||||
expect(archive).toEqual({
|
|
||||||
url: "https://github.com/supabase/cli/releases/download/v2.99.0/supabase_2.99.0_darwin_arm64.tar.gz",
|
|
||||||
format: "tar",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("authenticates latest release lookup when a GitHub token is provided", async () => {
|
|
||||||
process.env[GITHUB_TOKEN_ENV] = "ghs_test-token";
|
|
||||||
const fetch = mockLatestRelease("v2.99.0");
|
|
||||||
const { getDownloadArchive } = await getMainModule();
|
|
||||||
|
|
||||||
await getDownloadArchive("latest", "darwin", "arm64");
|
|
||||||
|
|
||||||
expect(fetch).toHaveBeenCalledWith(GITHUB_RELEASES_API, {
|
|
||||||
headers: expect.objectContaining({
|
|
||||||
Accept: "application/vnd.github+json",
|
|
||||||
Authorization: "Bearer ghs_test-token",
|
|
||||||
"X-GitHub-Api-Version": "2022-11-28",
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("awaits the action entrypoint with omitted version and latest fallback", async () => {
|
|
||||||
process.env.GITHUB_WORKSPACE = repo;
|
|
||||||
mockLatestRelease();
|
|
||||||
const cliDir = createFakeCli("supabase 2.84.2");
|
|
||||||
let startDownload!: () => void;
|
|
||||||
let finishDownload!: () => void;
|
|
||||||
const downloadStarted = new Promise<void>((resolve) => {
|
|
||||||
startDownload = resolve;
|
|
||||||
});
|
|
||||||
const downloadFinished = new Promise<string>((resolve) => {
|
|
||||||
finishDownload = () => resolve(path.join(os.tmpdir(), "supabase-cli.tar.gz"));
|
|
||||||
});
|
|
||||||
const spies = {
|
|
||||||
getInput: spyOn(core, "getInput").mockReturnValue(""),
|
|
||||||
setOutput: spyOn(core, "setOutput").mockImplementation(() => {}),
|
|
||||||
addPath: spyOn(core, "addPath").mockImplementation(() => {}),
|
|
||||||
exportVariable: spyOn(core, "exportVariable").mockImplementation(() => {}),
|
|
||||||
setFailed: spyOn(core, "setFailed").mockImplementation(() => {}),
|
|
||||||
downloadTool: spyOn(tc, "downloadTool").mockImplementation(async (url: string) => {
|
|
||||||
expect(url).toContain("/download/v2.99.0/supabase_2.99.0_");
|
|
||||||
startDownload();
|
|
||||||
return downloadFinished;
|
|
||||||
}),
|
|
||||||
extractTar: spyOn(tc, "extractTar").mockImplementation(async () => cliDir),
|
|
||||||
extractZip: spyOn(tc, "extractZip").mockImplementation(async () => cliDir),
|
|
||||||
};
|
|
||||||
const originalArgv1 = process.argv[1];
|
|
||||||
process.argv[1] = defaultEntrypoint;
|
|
||||||
|
|
||||||
try {
|
|
||||||
let importSettled = false;
|
|
||||||
const entrypoint = import(`./main.ts?entrypoint=${Date.now()}`).finally(() => {
|
|
||||||
importSettled = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
await downloadStarted;
|
|
||||||
await Bun.sleep(0);
|
|
||||||
|
|
||||||
expect(importSettled).toBe(false);
|
|
||||||
|
|
||||||
finishDownload();
|
|
||||||
await entrypoint;
|
|
||||||
} finally {
|
|
||||||
process.argv[1] = originalArgv1 ?? "";
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(spies.setOutput).toHaveBeenCalledWith("version", "supabase 2.84.2");
|
|
||||||
expect(spies.addPath).toHaveBeenCalledWith(cliDir);
|
|
||||||
expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io");
|
|
||||||
expect(spies.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("uses the root bun.lock version when version is omitted", async () => {
|
|
||||||
process.env.GITHUB_WORKSPACE = createWorkspace({
|
process.env.GITHUB_WORKSPACE = createWorkspace({
|
||||||
"bun.lock": createBunLock("2.41.0"),
|
"bun.lock": createBunLock("2.41.0", { integrity: "sha512-bun-lock" }),
|
||||||
});
|
});
|
||||||
const cliDir = createFakeCli("supabase 2.41.0");
|
const { resolvePackage } = await getMainModule();
|
||||||
const spies = createActionSpies("", cliDir, "/download/v2.41.0/supabase_");
|
|
||||||
const { run } = await getMainModule();
|
|
||||||
|
|
||||||
await run();
|
expect(resolvePackage("")).toEqual({
|
||||||
|
integrity: "sha512-bun-lock",
|
||||||
expect(spies.downloadTool).not.toHaveBeenCalledWith(expect.stringContaining("/latest/download/"));
|
spec: "supabase@2.41.0",
|
||||||
expect(spies.setOutput).toHaveBeenCalledWith("version", "supabase 2.41.0");
|
version: "2.41.0",
|
||||||
expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io");
|
});
|
||||||
expect(spies.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("uses the root pnpm-lock.yaml version when version is omitted", async () => {
|
test("uses the root pnpm-lock.yaml resolution when version is omitted", async () => {
|
||||||
process.env.GITHUB_WORKSPACE = createWorkspace({
|
process.env.GITHUB_WORKSPACE = createWorkspace({
|
||||||
"pnpm-lock.yaml": createPnpmLock("2.42.0"),
|
"pnpm-lock.yaml": createPnpmLock("2.42.0", { integrity: "sha512-pnpm-lock" }),
|
||||||
});
|
});
|
||||||
const cliDir = createFakeCli("supabase 2.42.0");
|
const { resolvePackage } = await getMainModule();
|
||||||
const spies = createActionSpies("", cliDir, "/download/v2.42.0/supabase_");
|
|
||||||
const { run } = await getMainModule();
|
|
||||||
|
|
||||||
await run();
|
expect(resolvePackage("")).toEqual({
|
||||||
|
integrity: "sha512-pnpm-lock",
|
||||||
expect(spies.setOutput).toHaveBeenCalledWith("version", "supabase 2.42.0");
|
spec: "supabase@2.42.0",
|
||||||
expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io");
|
version: "2.42.0",
|
||||||
expect(spies.setFailed).not.toHaveBeenCalled();
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("uses the root package-lock.json version when version is omitted", async () => {
|
test("uses the root package-lock.json resolution when version is omitted", async () => {
|
||||||
process.env.GITHUB_WORKSPACE = createWorkspace({
|
process.env.GITHUB_WORKSPACE = createWorkspace({
|
||||||
"package-lock.json": createPackageLock("2.43.0"),
|
"package-lock.json": createPackageLock("2.43.0", "sha512-package-lock"),
|
||||||
});
|
});
|
||||||
const cliDir = createFakeCli("supabase 2.43.0");
|
const { resolvePackage } = await getMainModule();
|
||||||
const spies = createActionSpies("", cliDir, "/download/v2.43.0/supabase_");
|
|
||||||
const { run } = await getMainModule();
|
|
||||||
|
|
||||||
await run();
|
expect(resolvePackage("")).toEqual({
|
||||||
|
integrity: "sha512-package-lock",
|
||||||
expect(spies.setOutput).toHaveBeenCalledWith("version", "supabase 2.43.0");
|
spec: "supabase@2.43.0",
|
||||||
expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io");
|
version: "2.43.0",
|
||||||
expect(spies.setFailed).not.toHaveBeenCalled();
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("falls through malformed lockfiles and uses the next supported root lockfile", async () => {
|
test("falls through malformed lockfiles and uses the next supported root lockfile", async () => {
|
||||||
@@ -379,60 +299,47 @@ test("falls through malformed lockfiles and uses the next supported root lockfil
|
|||||||
"bun.lock": "{ not valid",
|
"bun.lock": "{ not valid",
|
||||||
"package-lock.json": createPackageLock("2.44.0"),
|
"package-lock.json": createPackageLock("2.44.0"),
|
||||||
});
|
});
|
||||||
const cliDir = createFakeCli("supabase 2.44.0");
|
const { resolvePackage } = await getMainModule();
|
||||||
const spies = createActionSpies("", cliDir, "/download/v2.44.0/supabase_");
|
|
||||||
const { run } = await getMainModule();
|
|
||||||
|
|
||||||
await run();
|
expect(resolvePackage("")).toEqual({
|
||||||
|
integrity: "sha512-package-lock",
|
||||||
expect(spies.setOutput).toHaveBeenCalledWith("version", "supabase 2.44.0");
|
spec: "supabase@2.44.0",
|
||||||
expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io");
|
version: "2.44.0",
|
||||||
expect(spies.setFailed).not.toHaveBeenCalled();
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("falls back to latest when version is omitted and no supported root lockfile is present", async () => {
|
test("falls back to latest when version is omitted and no supported root lockfile is present", async () => {
|
||||||
process.env.GITHUB_WORKSPACE = createWorkspace({
|
process.env.GITHUB_WORKSPACE = createWorkspace({
|
||||||
"README.md": "# app\n",
|
"README.md": "# app\n",
|
||||||
});
|
});
|
||||||
mockLatestRelease();
|
const { resolvePackage } = await getMainModule();
|
||||||
const cliDir = createFakeCli("supabase 2.84.2");
|
|
||||||
const spies = createActionSpies("", cliDir, "/download/v2.99.0/supabase_2.99.0_");
|
|
||||||
const { run } = await getMainModule();
|
|
||||||
|
|
||||||
await run();
|
expect(resolvePackage("")).toEqual({
|
||||||
|
spec: "supabase@latest",
|
||||||
expect(spies.setOutput).toHaveBeenCalledWith("version", "supabase 2.84.2");
|
version: "latest",
|
||||||
expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io");
|
});
|
||||||
expect(spies.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("falls back to latest when version is omitted and no workspace is available", async () => {
|
test("falls back to latest when version is omitted and no workspace is available", async () => {
|
||||||
delete process.env.GITHUB_WORKSPACE;
|
delete process.env.GITHUB_WORKSPACE;
|
||||||
mockLatestRelease();
|
const { resolvePackage } = await getMainModule();
|
||||||
const cliDir = createFakeCli("supabase 2.84.2");
|
|
||||||
const spies = createActionSpies("", cliDir, "/download/v2.99.0/supabase_2.99.0_");
|
|
||||||
const { run } = await getMainModule();
|
|
||||||
|
|
||||||
await run();
|
expect(resolvePackage("")).toEqual({
|
||||||
|
spec: "supabase@latest",
|
||||||
expect(spies.setOutput).toHaveBeenCalledWith("version", "supabase 2.84.2");
|
version: "latest",
|
||||||
expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io");
|
});
|
||||||
expect(spies.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("uses the declared bun.lock version when the resolved package entry is missing", async () => {
|
test("uses the declared bun.lock version when the resolved package entry is missing", async () => {
|
||||||
process.env.GITHUB_WORKSPACE = createWorkspace({
|
process.env.GITHUB_WORKSPACE = createWorkspace({
|
||||||
"bun.lock": createBunLock("2.44.1", { includePackageEntry: false, useDevDependency: true }),
|
"bun.lock": createBunLock("2.44.1", { includePackageEntry: false, useDevDependency: true }),
|
||||||
});
|
});
|
||||||
const cliDir = createFakeCli("supabase 2.44.1");
|
const { resolvePackage } = await getMainModule();
|
||||||
const spies = createActionSpies("", cliDir, "/download/v2.44.1/supabase_");
|
|
||||||
const { run } = await getMainModule();
|
|
||||||
|
|
||||||
await run();
|
expect(resolvePackage("")).toEqual({
|
||||||
|
spec: "supabase@2.44.1",
|
||||||
expect(spies.setOutput).toHaveBeenCalledWith("version", "supabase 2.44.1");
|
version: "2.44.1",
|
||||||
expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io");
|
});
|
||||||
expect(spies.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("falls through bun.lock without supabase and uses a pnpm string dependency version", async () => {
|
test("falls through bun.lock without supabase and uses a pnpm string dependency version", async () => {
|
||||||
@@ -440,73 +347,119 @@ test("falls through bun.lock without supabase and uses a pnpm string dependency
|
|||||||
"bun.lock": createBunLock("2.47.0", { includeDependency: false }),
|
"bun.lock": createBunLock("2.47.0", { includeDependency: false }),
|
||||||
"pnpm-lock.yaml": createPnpmLock("2.47.0", { asString: true }),
|
"pnpm-lock.yaml": createPnpmLock("2.47.0", { asString: true }),
|
||||||
});
|
});
|
||||||
const cliDir = createFakeCli("supabase 2.47.0");
|
const { resolvePackage } = await getMainModule();
|
||||||
const spies = createActionSpies("", cliDir, "/download/v2.47.0/supabase_");
|
|
||||||
const { run } = await getMainModule();
|
|
||||||
|
|
||||||
await run();
|
expect(resolvePackage("")).toEqual({
|
||||||
|
integrity: "sha512-pnpm",
|
||||||
expect(spies.setOutput).toHaveBeenCalledWith("version", "supabase 2.47.0");
|
spec: "supabase@2.47.0",
|
||||||
expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io");
|
version: "2.47.0",
|
||||||
expect(spies.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("falls through malformed pnpm lockfiles and uses the next supported root lockfile", async () => {
|
|
||||||
process.env.GITHUB_WORKSPACE = createWorkspace({
|
|
||||||
"pnpm-lock.yaml": "not: [valid",
|
|
||||||
"package-lock.json": createPackageLock("2.48.0"),
|
|
||||||
});
|
|
||||||
const cliDir = createFakeCli("supabase 2.48.0");
|
|
||||||
const spies = createActionSpies("", cliDir, "/download/v2.48.0/supabase_");
|
|
||||||
const { run } = await getMainModule();
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(spies.setOutput).toHaveBeenCalledWith("version", "supabase 2.48.0");
|
|
||||||
expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io");
|
|
||||||
expect(spies.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("falls through unreadable bun.lock paths and malformed package-lock files to latest", async () => {
|
|
||||||
const workspace = createWorkspace({
|
|
||||||
"package-lock.json": "{ invalid",
|
|
||||||
});
|
|
||||||
mkdirSync(path.join(workspace, "bun.lock"), { recursive: true });
|
|
||||||
process.env.GITHUB_WORKSPACE = workspace;
|
|
||||||
mockLatestRelease();
|
|
||||||
const cliDir = createFakeCli("supabase 2.84.2");
|
|
||||||
const spies = createActionSpies("", cliDir, "/download/v2.99.0/supabase_2.99.0_");
|
|
||||||
const { run } = await getMainModule();
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(spies.setOutput).toHaveBeenCalledWith("version", "supabase 2.84.2");
|
|
||||||
expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io");
|
|
||||||
expect(spies.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("falls back to latest when a pnpm dependency entry has no concrete version", async () => {
|
test("falls back to latest when a pnpm dependency entry has no concrete version", async () => {
|
||||||
process.env.GITHUB_WORKSPACE = createWorkspace({
|
process.env.GITHUB_WORKSPACE = createWorkspace({
|
||||||
"pnpm-lock.yaml": createPnpmLock("2.49.0", { includeVersion: false }),
|
"pnpm-lock.yaml": createPnpmLock("2.49.0", { includeVersion: false }),
|
||||||
});
|
});
|
||||||
mockLatestRelease();
|
const { resolvePackage } = await getMainModule();
|
||||||
const cliDir = createFakeCli("supabase 2.84.2");
|
|
||||||
const spies = createActionSpies("", cliDir, "/download/v2.99.0/supabase_2.99.0_");
|
expect(resolvePackage("")).toEqual({
|
||||||
|
spec: "supabase@latest",
|
||||||
|
version: "latest",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("installs the CLI with npm into an isolated prefix", async () => {
|
||||||
|
const logPath = installFakeNpm();
|
||||||
|
const { installCli } = await getMainModule();
|
||||||
|
|
||||||
|
const cliPath = await installCli({
|
||||||
|
spec: "supabase@2.101.0",
|
||||||
|
version: "2.101.0",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(cliPath).toContain(`${path.sep}node_modules${path.sep}.bin`);
|
||||||
|
expect(readNpmCalls(logPath)).toEqual([
|
||||||
|
[
|
||||||
|
"install",
|
||||||
|
"--prefix",
|
||||||
|
expect.any(String),
|
||||||
|
"--omit=dev",
|
||||||
|
"--no-audit",
|
||||||
|
"--no-fund",
|
||||||
|
"--no-package-lock",
|
||||||
|
"--ignore-scripts",
|
||||||
|
"supabase@2.101.0",
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("verifies lockfile integrity before installing", async () => {
|
||||||
|
const logPath = installFakeNpm("supabase 2.101.0", "sha512-lock");
|
||||||
|
const { installCli } = await getMainModule();
|
||||||
|
|
||||||
|
await installCli({
|
||||||
|
integrity: "sha512-lock",
|
||||||
|
spec: "supabase@2.101.0",
|
||||||
|
version: "2.101.0",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readNpmCalls(logPath)).toEqual([
|
||||||
|
["view", "supabase@2.101.0", "dist.integrity", "--json"],
|
||||||
|
[
|
||||||
|
"install",
|
||||||
|
"--prefix",
|
||||||
|
expect.any(String),
|
||||||
|
"--omit=dev",
|
||||||
|
"--no-audit",
|
||||||
|
"--no-fund",
|
||||||
|
"--no-package-lock",
|
||||||
|
"--ignore-scripts",
|
||||||
|
"supabase@2.101.0",
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("fails when lockfile integrity does not match the registry", async () => {
|
||||||
|
installFakeNpm("supabase 2.101.0", "sha512-registry");
|
||||||
|
const { installCli } = await getMainModule();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await installCli({
|
||||||
|
integrity: "sha512-lock",
|
||||||
|
spec: "supabase@2.101.0",
|
||||||
|
version: "2.101.0",
|
||||||
|
});
|
||||||
|
throw new Error("Expected installCli to reject");
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toEqual(
|
||||||
|
new Error("Lockfile integrity for supabase@2.101.0 does not match the npm registry"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("runs the action with a package-lock resolution", async () => {
|
||||||
|
const logPath = installFakeNpm("supabase 2.43.0", "sha512-package-lock");
|
||||||
|
process.env.GITHUB_WORKSPACE = createWorkspace({
|
||||||
|
"package-lock.json": createPackageLock("2.43.0", "sha512-package-lock"),
|
||||||
|
});
|
||||||
|
const spies = createActionSpies("");
|
||||||
const { run } = await getMainModule();
|
const { run } = await getMainModule();
|
||||||
|
|
||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(spies.setOutput).toHaveBeenCalledWith("version", "supabase 2.84.2");
|
expect(readNpmCalls(logPath)[0]).toEqual(["view", "supabase@2.43.0", "dist.integrity", "--json"]);
|
||||||
|
expect(spies.setOutput).toHaveBeenCalledWith("version", "supabase 2.43.0");
|
||||||
|
expect(spies.addPath).toHaveBeenCalledWith(expect.stringContaining("node_modules"));
|
||||||
expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io");
|
expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io");
|
||||||
expect(spies.setFailed).not.toHaveBeenCalled();
|
expect(spies.setFailed).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("explicit version overrides detected root lockfiles", async () => {
|
test("explicit version overrides detected root lockfiles", async () => {
|
||||||
|
installFakeNpm("supabase 1.0.0");
|
||||||
process.env.GITHUB_WORKSPACE = createWorkspace({
|
process.env.GITHUB_WORKSPACE = createWorkspace({
|
||||||
"bun.lock": createBunLock("2.45.0"),
|
"bun.lock": createBunLock("2.45.0"),
|
||||||
});
|
});
|
||||||
const cliDir = createFakeCli("supabase 1.0.0");
|
const spies = createActionSpies("1.0.0");
|
||||||
const spies = createActionSpies("1.0.0", cliDir, "/download/v1.0.0/supabase_1.0.0_");
|
|
||||||
const { run } = await getMainModule();
|
const { run } = await getMainModule();
|
||||||
|
|
||||||
await run();
|
await run();
|
||||||
@@ -517,11 +470,11 @@ test("explicit version overrides detected root lockfiles", async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("fails when the installed CLI does not report a version", async () => {
|
test("fails when the installed CLI does not report a version", async () => {
|
||||||
|
installFakeNpm("");
|
||||||
process.env.GITHUB_WORKSPACE = createWorkspace({
|
process.env.GITHUB_WORKSPACE = createWorkspace({
|
||||||
"package-lock.json": createPackageLock("2.46.0"),
|
"package-lock.json": createPackageLock("2.46.0", "sha512-test"),
|
||||||
});
|
});
|
||||||
const cliDir = createFakeCli("");
|
const spies = createActionSpies("");
|
||||||
const spies = createActionSpies("", cliDir, "/download/v2.46.0/supabase_");
|
|
||||||
const { run } = await getMainModule();
|
const { run } = await getMainModule();
|
||||||
|
|
||||||
await run();
|
await run();
|
||||||
|
|||||||
313
src/main.ts
313
src/main.ts
@@ -1,22 +1,20 @@
|
|||||||
import { $, semver } from "bun";
|
import { semver } from "bun";
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import * as tc from "@actions/tool-cache";
|
import { existsSync, mkdtempSync, readFileSync } from "node:fs";
|
||||||
import { existsSync, readFileSync } from "node:fs";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
export const CLI_CONFIG_REGISTRY = "SUPABASE_INTERNAL_IMAGE_REGISTRY";
|
export const CLI_CONFIG_REGISTRY = "SUPABASE_INTERNAL_IMAGE_REGISTRY";
|
||||||
const REGISTRY_VERSION = "1.28.0";
|
const REGISTRY_VERSION = "1.28.0";
|
||||||
const VERSIONED_ARCHIVE_VERSION = "2.99.0";
|
|
||||||
const DEFAULT_VERSION = "latest";
|
const DEFAULT_VERSION = "latest";
|
||||||
const GITHUB_RELEASES_API = "https://api.github.com/repos/supabase/cli/releases/latest";
|
const NPM_PACKAGE = "supabase";
|
||||||
const GITHUB_TOKEN_ENV = "SUPABASE_CLI_GITHUB_TOKEN";
|
const NPM_EXECUTABLE_ENV = "SUPABASE_SETUP_CLI_NPM";
|
||||||
|
|
||||||
type ArchiveFormat = "apk" | "tar" | "zip";
|
type PackageResolution = {
|
||||||
|
spec: string;
|
||||||
type DownloadArchive = {
|
version: string;
|
||||||
url: string;
|
integrity?: string;
|
||||||
format: ArchiveFormat;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type BunLock = {
|
type BunLock = {
|
||||||
@@ -35,6 +33,12 @@ type PnpmDependency =
|
|||||||
version?: string;
|
version?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type PnpmPackage = {
|
||||||
|
resolution?: {
|
||||||
|
integrity?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
type PnpmLock = {
|
type PnpmLock = {
|
||||||
importers?: {
|
importers?: {
|
||||||
".": {
|
".": {
|
||||||
@@ -42,21 +46,14 @@ type PnpmLock = {
|
|||||||
devDependencies?: Record<string, PnpmDependency>;
|
devDependencies?: Record<string, PnpmDependency>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
packages?: Record<string, PnpmPackage>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type PackageLock = {
|
type PackageLock = {
|
||||||
packages?: Record<string, { version?: string }>;
|
packages?: Record<string, { integrity?: string; version?: string }>;
|
||||||
dependencies?: Record<string, { version?: string }>;
|
dependencies?: Record<string, { integrity?: string; version?: string }>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getArchivePlatform(platform: NodeJS.Platform): string {
|
|
||||||
return platform === "win32" ? "windows" : platform;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getArchiveArch(arch: NodeJS.Architecture): string {
|
|
||||||
return arch === "x64" ? "amd64" : arch;
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractConcreteVersion(raw: string | undefined): string | null {
|
function extractConcreteVersion(raw: string | undefined): string | null {
|
||||||
if (!raw) {
|
if (!raw) {
|
||||||
return null;
|
return null;
|
||||||
@@ -70,6 +67,16 @@ function normalizeVersion(version: string): string {
|
|||||||
return version.replace(/^v/i, "");
|
return version.replace(/^v/i, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toPackageResolution(version: string, integrity?: string): PackageResolution {
|
||||||
|
const normalizedVersion = normalizeVersion(version);
|
||||||
|
|
||||||
|
return {
|
||||||
|
spec: `${NPM_PACKAGE}@${normalizedVersion}`,
|
||||||
|
version: normalizedVersion,
|
||||||
|
integrity,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function readWorkspaceLockfile(workspaceRoot: string, filename: string): string | null {
|
function readWorkspaceLockfile(workspaceRoot: string, filename: string): string | null {
|
||||||
const filePath = path.join(workspaceRoot, filename);
|
const filePath = path.join(workspaceRoot, filename);
|
||||||
|
|
||||||
@@ -84,7 +91,7 @@ function readWorkspaceLockfile(workspaceRoot: string, filename: string): string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function detectVersionFromBunLock(workspaceRoot: string): string | null {
|
function detectResolutionFromBunLock(workspaceRoot: string): PackageResolution | null {
|
||||||
const text = readWorkspaceLockfile(workspaceRoot, "bun.lock");
|
const text = readWorkspaceLockfile(workspaceRoot, "bun.lock");
|
||||||
|
|
||||||
if (!text) {
|
if (!text) {
|
||||||
@@ -95,24 +102,28 @@ function detectVersionFromBunLock(workspaceRoot: string): string | null {
|
|||||||
const lockfile = JSON.parse(text.replace(/,\s*([}\]])/g, "$1")) as BunLock;
|
const lockfile = JSON.parse(text.replace(/,\s*([}\]])/g, "$1")) as BunLock;
|
||||||
const rootWorkspace = lockfile.workspaces?.[""];
|
const rootWorkspace = lockfile.workspaces?.[""];
|
||||||
const declaredVersion =
|
const declaredVersion =
|
||||||
rootWorkspace?.dependencies?.supabase ?? rootWorkspace?.devDependencies?.supabase;
|
rootWorkspace?.dependencies?.[NPM_PACKAGE] ?? rootWorkspace?.devDependencies?.[NPM_PACKAGE];
|
||||||
|
|
||||||
if (!declaredVersion) {
|
if (!declaredVersion) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolvedPackage = lockfile.packages?.supabase;
|
const resolvedPackage = lockfile.packages?.[NPM_PACKAGE];
|
||||||
if (Array.isArray(resolvedPackage) && typeof resolvedPackage[0] === "string") {
|
if (Array.isArray(resolvedPackage) && typeof resolvedPackage[0] === "string") {
|
||||||
return extractConcreteVersion(resolvedPackage[0]);
|
const version = extractConcreteVersion(resolvedPackage[0]);
|
||||||
|
const integrity = typeof resolvedPackage[3] === "string" ? resolvedPackage[3] : undefined;
|
||||||
|
|
||||||
|
return version ? toPackageResolution(version, integrity) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return extractConcreteVersion(declaredVersion);
|
const version = extractConcreteVersion(declaredVersion);
|
||||||
|
return version ? toPackageResolution(version) : null;
|
||||||
} catch {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function detectVersionFromPnpmLock(workspaceRoot: string): string | null {
|
function detectResolutionFromPnpmLock(workspaceRoot: string): PackageResolution | null {
|
||||||
const text = readWorkspaceLockfile(workspaceRoot, "pnpm-lock.yaml");
|
const text = readWorkspaceLockfile(workspaceRoot, "pnpm-lock.yaml");
|
||||||
|
|
||||||
if (!text) {
|
if (!text) {
|
||||||
@@ -123,19 +134,29 @@ function detectVersionFromPnpmLock(workspaceRoot: string): string | null {
|
|||||||
const lockfile = Bun.YAML.parse(text) as PnpmLock;
|
const lockfile = Bun.YAML.parse(text) as PnpmLock;
|
||||||
const rootImporter = lockfile.importers?.["."];
|
const rootImporter = lockfile.importers?.["."];
|
||||||
const dependency =
|
const dependency =
|
||||||
rootImporter?.dependencies?.supabase ?? rootImporter?.devDependencies?.supabase;
|
rootImporter?.dependencies?.[NPM_PACKAGE] ?? rootImporter?.devDependencies?.[NPM_PACKAGE];
|
||||||
|
const version =
|
||||||
|
typeof dependency === "string"
|
||||||
|
? extractConcreteVersion(dependency)
|
||||||
|
: extractConcreteVersion(dependency?.version);
|
||||||
|
|
||||||
if (typeof dependency === "string") {
|
if (!version) {
|
||||||
return extractConcreteVersion(dependency);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return extractConcreteVersion(dependency?.version);
|
const integrity = Object.entries(lockfile.packages ?? {}).find(
|
||||||
|
([packageKey]) =>
|
||||||
|
packageKey === `${NPM_PACKAGE}@${version}` ||
|
||||||
|
packageKey.startsWith(`/${NPM_PACKAGE}@${version}`),
|
||||||
|
)?.[1].resolution?.integrity;
|
||||||
|
|
||||||
|
return toPackageResolution(version, integrity);
|
||||||
} catch {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function detectVersionFromPackageLock(workspaceRoot: string): string | null {
|
function detectResolutionFromPackageLock(workspaceRoot: string): PackageResolution | null {
|
||||||
const text = readWorkspaceLockfile(workspaceRoot, "package-lock.json");
|
const text = readWorkspaceLockfile(workspaceRoot, "package-lock.json");
|
||||||
|
|
||||||
if (!text) {
|
if (!text) {
|
||||||
@@ -144,147 +165,97 @@ function detectVersionFromPackageLock(workspaceRoot: string): string | null {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const lockfile = JSON.parse(text) as PackageLock;
|
const lockfile = JSON.parse(text) as PackageLock;
|
||||||
|
const packageEntry = lockfile.packages?.[`node_modules/${NPM_PACKAGE}`];
|
||||||
|
const dependencyEntry = lockfile.dependencies?.[NPM_PACKAGE];
|
||||||
|
const version =
|
||||||
|
extractConcreteVersion(packageEntry?.version) ??
|
||||||
|
extractConcreteVersion(dependencyEntry?.version);
|
||||||
|
|
||||||
return (
|
return version
|
||||||
extractConcreteVersion(lockfile.packages?.["node_modules/supabase"]?.version) ??
|
? toPackageResolution(version, packageEntry?.integrity ?? dependencyEntry?.integrity)
|
||||||
extractConcreteVersion(lockfile.dependencies?.supabase?.version)
|
: null;
|
||||||
);
|
|
||||||
} catch {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveVersion(inputVersion: string): string {
|
export function resolvePackage(inputVersion: string): PackageResolution {
|
||||||
const requestedVersion = inputVersion.trim();
|
const requestedVersion = inputVersion.trim();
|
||||||
|
|
||||||
if (requestedVersion) {
|
if (requestedVersion) {
|
||||||
return requestedVersion;
|
return toPackageResolution(requestedVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
const workspaceRoot = process.env.GITHUB_WORKSPACE?.trim();
|
const workspaceRoot = process.env.GITHUB_WORKSPACE?.trim();
|
||||||
|
|
||||||
if (!workspaceRoot) {
|
if (!workspaceRoot) {
|
||||||
return DEFAULT_VERSION;
|
return toPackageResolution(DEFAULT_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
detectVersionFromBunLock(workspaceRoot) ??
|
detectResolutionFromBunLock(workspaceRoot) ??
|
||||||
detectVersionFromPnpmLock(workspaceRoot) ??
|
detectResolutionFromPnpmLock(workspaceRoot) ??
|
||||||
detectVersionFromPackageLock(workspaceRoot) ??
|
detectResolutionFromPackageLock(workspaceRoot) ??
|
||||||
DEFAULT_VERSION
|
toPackageResolution(DEFAULT_VERSION)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resolveLatestVersion(): Promise<string> {
|
async function verifyExpectedIntegrity(resolution: PackageResolution): Promise<void> {
|
||||||
const headers: Record<string, string> = {
|
if (!resolution.integrity) {
|
||||||
Accept: "application/vnd.github+json",
|
return;
|
||||||
"X-GitHub-Api-Version": "2022-11-28",
|
|
||||||
};
|
|
||||||
const githubToken = process.env[GITHUB_TOKEN_ENV]?.trim();
|
|
||||||
|
|
||||||
if (githubToken) {
|
|
||||||
headers.Authorization = `Bearer ${githubToken}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch(GITHUB_RELEASES_API, { headers });
|
const output = await runNpm(["view", resolution.spec, "dist.integrity", "--json"]);
|
||||||
if (!response.ok) {
|
const registryIntegrity = JSON.parse(output) as unknown;
|
||||||
throw new Error(`Failed to resolve latest Supabase CLI release: ${response.statusText}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const release = (await response.json()) as { tag_name?: unknown };
|
if (registryIntegrity !== resolution.integrity) {
|
||||||
if (typeof release.tag_name !== "string") {
|
throw new Error(`Lockfile integrity for ${resolution.spec} does not match the npm registry`);
|
||||||
throw new Error("Failed to resolve latest Supabase CLI release: missing tag name");
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalizeVersion(release.tag_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getArchiveFormat(
|
|
||||||
version: string,
|
|
||||||
platform: NodeJS.Platform,
|
|
||||||
isMuslLinux: boolean,
|
|
||||||
): ArchiveFormat {
|
|
||||||
if (
|
|
||||||
platform === "linux" &&
|
|
||||||
isMuslLinux &&
|
|
||||||
semver.order(version, VERSIONED_ARCHIVE_VERSION) >= 0
|
|
||||||
) {
|
|
||||||
return "apk";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (platform === "win32" && semver.order(version, VERSIONED_ARCHIVE_VERSION) >= 0) {
|
|
||||||
return "zip";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "tar";
|
|
||||||
}
|
|
||||||
|
|
||||||
function getArchiveFilename(
|
|
||||||
version: string,
|
|
||||||
platform: NodeJS.Platform,
|
|
||||||
arch: NodeJS.Architecture,
|
|
||||||
archiveFormat: ArchiveFormat,
|
|
||||||
): string {
|
|
||||||
const archivePlatform = getArchivePlatform(platform);
|
|
||||||
const archiveArch = getArchiveArch(arch);
|
|
||||||
|
|
||||||
if (semver.order(version, REGISTRY_VERSION) === -1) {
|
|
||||||
return `supabase_${version}_${archivePlatform}_${archiveArch}.tar.gz`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (platform === "linux" && archiveFormat === "apk") {
|
|
||||||
return `supabase_${version}_${archivePlatform}_${archiveArch}.apk`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (semver.order(version, VERSIONED_ARCHIVE_VERSION) >= 0) {
|
|
||||||
const extension = platform === "win32" ? "zip" : "tar.gz";
|
|
||||||
return `supabase_${version}_${archivePlatform}_${archiveArch}.${extension}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `supabase_${archivePlatform}_${archiveArch}.tar.gz`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getDownloadArchive(
|
|
||||||
version: string,
|
|
||||||
platform = process.platform,
|
|
||||||
arch = process.arch,
|
|
||||||
isMuslLinux?: boolean,
|
|
||||||
): Promise<DownloadArchive> {
|
|
||||||
const resolvedVersion =
|
|
||||||
version.toLowerCase() === "latest" ? await resolveLatestVersion() : normalizeVersion(version);
|
|
||||||
const format = getArchiveFormat(
|
|
||||||
resolvedVersion,
|
|
||||||
platform,
|
|
||||||
isMuslLinux ?? (await detectMuslLinux(platform)),
|
|
||||||
);
|
|
||||||
const filename = getArchiveFilename(resolvedVersion, platform, arch, format);
|
|
||||||
|
|
||||||
return {
|
|
||||||
url: `https://github.com/supabase/cli/releases/download/v${resolvedVersion}/${filename}`,
|
|
||||||
format,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function detectMuslLinux(platform = process.platform): Promise<boolean> {
|
|
||||||
if (platform !== "linux") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existsSync("/etc/alpine-release")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const output = await $`ldd --version`.quiet().text();
|
|
||||||
return output.toLowerCase().includes("musl");
|
|
||||||
} catch (error) {
|
|
||||||
const output = error instanceof Error ? error.message : String(error);
|
|
||||||
return output.toLowerCase().includes("musl");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCliPath(extractedPath: string, archiveFormat: ArchiveFormat): string {
|
function createInstallRoot(): string {
|
||||||
return archiveFormat === "apk" ? path.join(extractedPath, "usr", "bin") : extractedPath;
|
const tempRoot = process.env.RUNNER_TEMP?.trim() || os.tmpdir();
|
||||||
|
return mkdtempSync(path.join(tempRoot, "setup-cli-"));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runNpm(args: string[]): Promise<string> {
|
||||||
|
const executable = process.env[NPM_EXECUTABLE_ENV]?.trim() || "npm";
|
||||||
|
const proc = Bun.spawn([executable, ...args], {
|
||||||
|
env: process.env,
|
||||||
|
stderr: "pipe",
|
||||||
|
stdout: "pipe",
|
||||||
|
});
|
||||||
|
const [stdout, stderr, exitCode] = await Promise.all([
|
||||||
|
new Response(proc.stdout).text(),
|
||||||
|
new Response(proc.stderr).text(),
|
||||||
|
proc.exited,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
throw new Error(stderr.trim() || `npm ${args.join(" ")} failed`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdout;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function installCli(resolution: PackageResolution): Promise<string> {
|
||||||
|
await verifyExpectedIntegrity(resolution);
|
||||||
|
|
||||||
|
const installRoot = createInstallRoot();
|
||||||
|
|
||||||
|
await runNpm([
|
||||||
|
"install",
|
||||||
|
"--prefix",
|
||||||
|
installRoot,
|
||||||
|
"--omit=dev",
|
||||||
|
"--no-audit",
|
||||||
|
"--no-fund",
|
||||||
|
"--no-package-lock",
|
||||||
|
"--ignore-scripts",
|
||||||
|
resolution.spec,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return path.join(installRoot, "node_modules", ".bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCliExecutablePath(cliPath: string): string {
|
function getCliExecutablePath(cliPath: string): string {
|
||||||
@@ -292,21 +263,36 @@ function getCliExecutablePath(cliPath: string): string {
|
|||||||
return path.join(cliPath, "supabase");
|
return path.join(cliPath, "supabase");
|
||||||
}
|
}
|
||||||
|
|
||||||
const exePath = path.join(cliPath, "supabase.exe");
|
|
||||||
if (existsSync(exePath)) {
|
|
||||||
return exePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cmdPath = path.join(cliPath, "supabase.cmd");
|
const cmdPath = path.join(cliPath, "supabase.cmd");
|
||||||
if (existsSync(cmdPath)) {
|
if (existsSync(cmdPath)) {
|
||||||
return cmdPath;
|
return cmdPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const exePath = path.join(cliPath, "supabase.exe");
|
||||||
|
if (existsSync(exePath)) {
|
||||||
|
return exePath;
|
||||||
|
}
|
||||||
|
|
||||||
return path.join(cliPath, "supabase");
|
return path.join(cliPath, "supabase");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function determineInstalledVersion(cliPath: string): Promise<string> {
|
export async function determineInstalledVersion(cliPath: string): Promise<string> {
|
||||||
const version = (await $`${getCliExecutablePath(cliPath)} --version`.text()).trim();
|
const executable = getCliExecutablePath(cliPath);
|
||||||
|
const proc = Bun.spawn([executable, "--version"], {
|
||||||
|
stderr: "pipe",
|
||||||
|
stdout: "pipe",
|
||||||
|
});
|
||||||
|
const [stdout, stderr, exitCode] = await Promise.all([
|
||||||
|
new Response(proc.stdout).text(),
|
||||||
|
new Response(proc.stderr).text(),
|
||||||
|
proc.exited,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
throw new Error(stderr.trim() || "Could not determine installed Supabase CLI version");
|
||||||
|
}
|
||||||
|
|
||||||
|
const version = stdout.trim();
|
||||||
if (!version) {
|
if (!version) {
|
||||||
throw new Error("Could not determine installed Supabase CLI version");
|
throw new Error("Could not determine installed Supabase CLI version");
|
||||||
}
|
}
|
||||||
@@ -314,21 +300,24 @@ export async function determineInstalledVersion(cliPath: string): Promise<string
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldUseGhcrRegistry(requestedVersion: string, installedVersion: string): boolean {
|
||||||
|
if (requestedVersion.toLowerCase() === DEFAULT_VERSION) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const concreteVersion = extractConcreteVersion(installedVersion);
|
||||||
|
return concreteVersion !== null && semver.order(concreteVersion, REGISTRY_VERSION) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
export async function run(): Promise<void> {
|
export async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const version = resolveVersion(core.getInput("version"));
|
const resolution = resolvePackage(core.getInput("version"));
|
||||||
const archive = await getDownloadArchive(version);
|
const cliPath = await installCli(resolution);
|
||||||
const archivePath = await tc.downloadTool(archive.url);
|
|
||||||
const extractedPath =
|
|
||||||
archive.format === "zip"
|
|
||||||
? await tc.extractZip(archivePath)
|
|
||||||
: await tc.extractTar(archivePath);
|
|
||||||
const cliPath = getCliPath(extractedPath, archive.format);
|
|
||||||
const installedVersion = await determineInstalledVersion(cliPath);
|
const installedVersion = await determineInstalledVersion(cliPath);
|
||||||
core.setOutput("version", installedVersion);
|
core.setOutput("version", installedVersion);
|
||||||
core.addPath(cliPath);
|
core.addPath(cliPath);
|
||||||
|
|
||||||
if (version.toLowerCase() === "latest" || semver.order(version, REGISTRY_VERSION) >= 0) {
|
if (shouldUseGhcrRegistry(resolution.version, installedVersion)) {
|
||||||
core.exportVariable(CLI_CONFIG_REGISTRY, "ghcr.io");
|
core.exportVariable(CLI_CONFIG_REGISTRY, "ghcr.io");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user