mirror of
https://github.com/supabase/setup-cli.git
synced 2026-05-13 11:26:59 +00:00
feat: caching
This commit is contained in:
51
README.md
51
README.md
@@ -40,6 +40,22 @@ steps:
|
|||||||
version: 2.84.2
|
version: 2.84.2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Cache Docker images used by `supabase start` across workflow runs:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: supabase/setup-cli@v2
|
||||||
|
with:
|
||||||
|
version: 2.84.2
|
||||||
|
cache: true
|
||||||
|
- run: supabase start
|
||||||
|
```
|
||||||
|
|
||||||
|
The first run still pulls images from the registry. Later runs can restore the
|
||||||
|
same image set from the GitHub Actions cache before `supabase start` runs, and
|
||||||
|
the action saves newly pulled Supabase images at the end of a successful job.
|
||||||
|
|
||||||
Run `supabase db start` to execute all migrations on a fresh database:
|
Run `supabase db start` to execute all migrations on a fresh database:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -59,8 +75,17 @@ 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 |
|
||||||
|
| `cache` | Boolean | Cache Docker images used by Supabase local development | `false` | false |
|
||||||
|
| `cache-key` | String | Explicit cache key for Supabase Docker images | Generated from runner and config | false |
|
||||||
|
|
||||||
|
The action exposes these outputs:
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
| ----------- | ------------------------------------------------------ |
|
||||||
|
| `version` | Version of installed Supabase CLI |
|
||||||
|
| `cache-hit` | Whether an exact Supabase Docker image cache was found |
|
||||||
|
|
||||||
## Advanced Usage
|
## Advanced Usage
|
||||||
|
|
||||||
@@ -101,6 +126,8 @@ Export local Supabase env vars for app tests:
|
|||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: supabase/setup-cli@v2
|
- uses: supabase/setup-cli@v2
|
||||||
|
with:
|
||||||
|
cache: true
|
||||||
- run: supabase init
|
- run: supabase init
|
||||||
- run: supabase start
|
- run: supabase start
|
||||||
- name: Export local Supabase env vars
|
- name: Export local Supabase env vars
|
||||||
@@ -113,6 +140,22 @@ steps:
|
|||||||
- run: bun test
|
- run: bun test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Customize the Docker image cache key when the image set depends on your workflow
|
||||||
|
flags, generated config, or monorepo layout:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: supabase/setup-cli@v2
|
||||||
|
with:
|
||||||
|
cache: true
|
||||||
|
cache-key: supabase-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('supabase/config.toml') }}-start-all
|
||||||
|
- run: supabase start
|
||||||
|
```
|
||||||
|
|
||||||
|
Avoid running `docker system prune -a` before the job ends if you want the
|
||||||
|
post-action cache save to include images pulled by `supabase start`.
|
||||||
|
|
||||||
## Develop
|
## Develop
|
||||||
|
|
||||||
After you've cloned the repository to your local machine or codespace, you'll
|
After you've cloned the repository to your local machine or codespace, you'll
|
||||||
@@ -136,6 +179,12 @@ need to perform a few setup steps before you can work on the action.
|
|||||||
bun test
|
bun test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
1. :package: Build the bundled action entrypoints
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
1. :mag: Run the full local CI suite
|
1. :mag: Run the full local CI suite
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
33
action.yml
33
action.yml
@@ -5,27 +5,20 @@ inputs:
|
|||||||
version:
|
version:
|
||||||
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
|
||||||
|
cache:
|
||||||
|
description: Cache Docker images used by Supabase local development commands.
|
||||||
|
required: false
|
||||||
|
default: "false"
|
||||||
|
cache-key:
|
||||||
|
description: Optional explicit cache key for Supabase Docker images.
|
||||||
|
required: false
|
||||||
outputs:
|
outputs:
|
||||||
version:
|
version:
|
||||||
description: Version of installed Supabase CLI
|
description: Version of installed Supabase CLI
|
||||||
value: ${{ steps.setup-cli.outputs.version }}
|
cache-hit:
|
||||||
|
description: Whether an exact Supabase Docker image cache was restored.
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: node24
|
||||||
steps:
|
main: dist/main.js
|
||||||
- name: Setup Bun
|
post: dist/post.js
|
||||||
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
post-if: success()
|
||||||
with:
|
|
||||||
bun-version-file: ${{ github.action_path }}/.bun-version
|
|
||||||
|
|
||||||
- name: Install Action Dependencies
|
|
||||||
shell: bash
|
|
||||||
working-directory: ${{ github.action_path }}
|
|
||||||
run: bun install --frozen-lockfile --production
|
|
||||||
|
|
||||||
- id: setup-cli
|
|
||||||
name: Setup Supabase CLI
|
|
||||||
shell: bash
|
|
||||||
working-directory: ${{ github.action_path }}
|
|
||||||
env:
|
|
||||||
INPUT_VERSION: ${{ inputs.version }}
|
|
||||||
run: bun src/main.ts
|
|
||||||
|
|||||||
88
bun.lock
88
bun.lock
@@ -5,12 +5,18 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "setup-cli",
|
"name": "setup-cli",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@actions/cache": "^6.0.0",
|
||||||
"@actions/core": "^3.0.0",
|
"@actions/core": "^3.0.0",
|
||||||
"@actions/tool-cache": "^4.0.0",
|
"@actions/tool-cache": "^4.0.0",
|
||||||
|
"js-yaml": "^4.1.1",
|
||||||
|
"semver": "^7.7.4",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/bun": "^1.0.10",
|
"@tsconfig/bun": "^1.0.10",
|
||||||
"@types/bun": "^1.3.11",
|
"@types/bun": "^1.3.11",
|
||||||
|
"@types/js-yaml": "^4.0.9",
|
||||||
|
"@types/node": "^24",
|
||||||
|
"@types/semver": "^7.7.1",
|
||||||
"@typescript/native-preview": "^7.0.0-dev.20260409.1",
|
"@typescript/native-preview": "^7.0.0-dev.20260409.1",
|
||||||
"oxfmt": "^0.44.0",
|
"oxfmt": "^0.44.0",
|
||||||
"oxlint": "^1.59.0",
|
"oxlint": "^1.59.0",
|
||||||
@@ -19,16 +25,46 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages": {
|
"packages": {
|
||||||
|
"@actions/cache": ["@actions/cache@6.0.0", "", { "dependencies": { "@actions/core": "^3.0.0", "@actions/exec": "^3.0.0", "@actions/glob": "^0.6.1", "@actions/http-client": "^4.0.0", "@actions/io": "^3.0.0", "@azure/core-rest-pipeline": "^1.22.0", "@azure/storage-blob": "^12.30.0", "@protobuf-ts/runtime-rpc": "^2.11.1", "semver": "^7.7.3" } }, "sha512-+tCs634SyGBQJ3KU1rtAVabmN/gYiT9WgzTSJzWwdPCLmM3zWrdbysaErKv8HyI6OozClrxNvDgPjJimbHZZvw=="],
|
||||||
|
|
||||||
"@actions/core": ["@actions/core@3.0.0", "", { "dependencies": { "@actions/exec": "^3.0.0", "@actions/http-client": "^4.0.0" } }, "sha512-zYt6cz+ivnTmiT/ksRVriMBOiuoUpDCJJlZ5KPl2/FRdvwU3f7MPh9qftvbkXJThragzUZieit2nyHUyw53Seg=="],
|
"@actions/core": ["@actions/core@3.0.0", "", { "dependencies": { "@actions/exec": "^3.0.0", "@actions/http-client": "^4.0.0" } }, "sha512-zYt6cz+ivnTmiT/ksRVriMBOiuoUpDCJJlZ5KPl2/FRdvwU3f7MPh9qftvbkXJThragzUZieit2nyHUyw53Seg=="],
|
||||||
|
|
||||||
"@actions/exec": ["@actions/exec@3.0.0", "", { "dependencies": { "@actions/io": "^3.0.2" } }, "sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw=="],
|
"@actions/exec": ["@actions/exec@3.0.0", "", { "dependencies": { "@actions/io": "^3.0.2" } }, "sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw=="],
|
||||||
|
|
||||||
|
"@actions/glob": ["@actions/glob@0.6.1", "", { "dependencies": { "@actions/core": "^3.0.0", "minimatch": "^3.0.4" } }, "sha512-K4+2Ac5ILcf2ySdJCha+Pop9NcKjxqCL4xL4zI50dgB2PbXgC0+AcP011xfH4Of6b4QEJJg8dyZYv7zl4byTsw=="],
|
||||||
|
|
||||||
"@actions/http-client": ["@actions/http-client@4.0.0", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^6.23.0" } }, "sha512-QuwPsgVMsD6qaPD57GLZi9sqzAZCtiJT8kVBCDpLtxhL5MydQ4gS+DrejtZZPdIYyB1e95uCK9Luyds7ybHI3g=="],
|
"@actions/http-client": ["@actions/http-client@4.0.0", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^6.23.0" } }, "sha512-QuwPsgVMsD6qaPD57GLZi9sqzAZCtiJT8kVBCDpLtxhL5MydQ4gS+DrejtZZPdIYyB1e95uCK9Luyds7ybHI3g=="],
|
||||||
|
|
||||||
"@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=="],
|
"@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=="],
|
||||||
|
|
||||||
|
"@azure/abort-controller": ["@azure/abort-controller@2.1.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA=="],
|
||||||
|
|
||||||
|
"@azure/core-auth": ["@azure/core-auth@1.10.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-util": "^1.13.0", "tslib": "^2.6.2" } }, "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg=="],
|
||||||
|
|
||||||
|
"@azure/core-client": ["@azure/core-client@1.10.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0", "@azure/core-tracing": "^1.3.0", "@azure/core-util": "^1.13.0", "@azure/logger": "^1.3.0", "tslib": "^2.6.2" } }, "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w=="],
|
||||||
|
|
||||||
|
"@azure/core-http-compat": ["@azure/core-http-compat@2.4.0", "", { "dependencies": { "@azure/abort-controller": "^2.1.2" }, "peerDependencies": { "@azure/core-client": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0" } }, "sha512-f1P96IB399YiN2ARYHP7EpZi3Bf3wH4SN2lGzrw7JVwm7bbsVYtf2iKSBwTywD2P62NOPZGHFSZi+6jjb75JuA=="],
|
||||||
|
|
||||||
|
"@azure/core-lro": ["@azure/core-lro@2.7.2", "", { "dependencies": { "@azure/abort-controller": "^2.0.0", "@azure/core-util": "^1.2.0", "@azure/logger": "^1.0.0", "tslib": "^2.6.2" } }, "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw=="],
|
||||||
|
|
||||||
|
"@azure/core-paging": ["@azure/core-paging@1.6.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA=="],
|
||||||
|
|
||||||
|
"@azure/core-rest-pipeline": ["@azure/core-rest-pipeline@1.23.0", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.10.0", "@azure/core-tracing": "^1.3.0", "@azure/core-util": "^1.13.0", "@azure/logger": "^1.3.0", "@typespec/ts-http-runtime": "^0.3.4", "tslib": "^2.6.2" } }, "sha512-Evs1INHo+jUjwHi1T6SG6Ua/LHOQBCLuKEEE6efIpt4ZOoNonaT1kP32GoOcdNDbfqsD2445CPri3MubBy5DEQ=="],
|
||||||
|
|
||||||
|
"@azure/core-tracing": ["@azure/core-tracing@1.3.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ=="],
|
||||||
|
|
||||||
|
"@azure/core-util": ["@azure/core-util@1.13.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A=="],
|
||||||
|
|
||||||
|
"@azure/core-xml": ["@azure/core-xml@1.5.1", "", { "dependencies": { "fast-xml-parser": "^5.5.9", "tslib": "^2.8.1" } }, "sha512-xcNRHqCoSp4AunOALEae6A8f3qATb83gSrm31Iqb01OzblvC3/W/bfXozcq78EzIdzZzuH1bZ2NvRR0TdX709w=="],
|
||||||
|
|
||||||
|
"@azure/logger": ["@azure/logger@1.3.0", "", { "dependencies": { "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA=="],
|
||||||
|
|
||||||
|
"@azure/storage-blob": ["@azure/storage-blob@12.31.0", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.9.0", "@azure/core-client": "^1.9.3", "@azure/core-http-compat": "^2.2.0", "@azure/core-lro": "^2.2.0", "@azure/core-paging": "^1.6.2", "@azure/core-rest-pipeline": "^1.19.1", "@azure/core-tracing": "^1.2.0", "@azure/core-util": "^1.11.0", "@azure/core-xml": "^1.4.5", "@azure/logger": "^1.1.4", "@azure/storage-common": "^12.3.0", "events": "^3.0.0", "tslib": "^2.8.1" } }, "sha512-DBgNv10aCSxopt92DkTDD0o9xScXeBqPKGmR50FPZQaEcH4JLQ+GEOGEDv19V5BMkB7kxr+m4h6il/cCDPvmHg=="],
|
||||||
|
|
||||||
|
"@azure/storage-common": ["@azure/storage-common@12.3.0", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.9.0", "@azure/core-http-compat": "^2.2.0", "@azure/core-rest-pipeline": "^1.19.1", "@azure/core-tracing": "^1.2.0", "@azure/core-util": "^1.11.0", "@azure/logger": "^1.1.4", "events": "^3.3.0", "tslib": "^2.8.1" } }, "sha512-/OFHhy86aG5Pe8dP5tsp+BuJ25JOAl9yaMU3WZbkeoiFMHFtJ7tu5ili7qEdBXNW9G5lDB19trwyI6V49F/8iQ=="],
|
||||||
|
|
||||||
"@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.44.0", "", { "os": "android", "cpu": "arm" }, "sha512-5UvghMd9SA/yvKTWCAxMAPXS1d2i054UeOf4iFjZjfayTwCINcC3oaSXjtbZfCaEpxgJod7XiOjTtby5yEv/BQ=="],
|
"@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.44.0", "", { "os": "android", "cpu": "arm" }, "sha512-5UvghMd9SA/yvKTWCAxMAPXS1d2i054UeOf4iFjZjfayTwCINcC3oaSXjtbZfCaEpxgJod7XiOjTtby5yEv/BQ=="],
|
||||||
|
|
||||||
"@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.44.0", "", { "os": "android", "cpu": "arm64" }, "sha512-IVudM1BWfvrYO++Khtzr8q9n5Rxu7msUvoFMqzGJVdX7HfUXUDHwaH2zHZNB58svx2J56pmCUzophyaPFkcG/A=="],
|
"@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.44.0", "", { "os": "android", "cpu": "arm64" }, "sha512-IVudM1BWfvrYO++Khtzr8q9n5Rxu7msUvoFMqzGJVdX7HfUXUDHwaH2zHZNB58svx2J56pmCUzophyaPFkcG/A=="],
|
||||||
@@ -117,11 +153,19 @@
|
|||||||
|
|
||||||
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-xkE7puteDS/vUyRngLXW0t8WgdWoS/tfxXjhP/P7SMqPDx+hs44SpssO3h3qmTqECYEuXBUPzcAw5257Ka+ofA=="],
|
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-xkE7puteDS/vUyRngLXW0t8WgdWoS/tfxXjhP/P7SMqPDx+hs44SpssO3h3qmTqECYEuXBUPzcAw5257Ka+ofA=="],
|
||||||
|
|
||||||
|
"@protobuf-ts/runtime": ["@protobuf-ts/runtime@2.11.1", "", {}, "sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ=="],
|
||||||
|
|
||||||
|
"@protobuf-ts/runtime-rpc": ["@protobuf-ts/runtime-rpc@2.11.1", "", { "dependencies": { "@protobuf-ts/runtime": "^2.11.1" } }, "sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ=="],
|
||||||
|
|
||||||
"@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.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="],
|
"@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@20.19.37", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw=="],
|
"@types/js-yaml": ["@types/js-yaml@4.0.9", "", {}, "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
|
||||||
|
|
||||||
|
"@types/semver": ["@types/semver@7.7.1", "", {}, "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA=="],
|
||||||
|
|
||||||
"@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260409.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260409.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260409.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260409.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260409.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260409.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260409.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260409.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-CV1HEMGo1xCySwUJbCQOF+mmrTue8KTJ1Od2kKWhcbOpu8fPBfaqIpbAM6tGLcNEykEjMMTYHc/VTLbMgxdScQ=="],
|
"@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260409.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260409.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260409.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260409.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260409.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260409.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260409.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260409.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-CV1HEMGo1xCySwUJbCQOF+mmrTue8KTJ1Od2kKWhcbOpu8fPBfaqIpbAM6tGLcNEykEjMMTYHc/VTLbMgxdScQ=="],
|
||||||
|
|
||||||
@@ -139,22 +183,62 @@
|
|||||||
|
|
||||||
"@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260409.1", "", { "os": "win32", "cpu": "x64" }, "sha512-WRd+JpQipTsE15QgYr3w7J0f1NKvGcq2QEgmcq8hB0WZA1X2WhQopNu+MpPQ3tdDD42VjMhm8ZoB8HpuOoXK5w=="],
|
"@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260409.1", "", { "os": "win32", "cpu": "x64" }, "sha512-WRd+JpQipTsE15QgYr3w7J0f1NKvGcq2QEgmcq8hB0WZA1X2WhQopNu+MpPQ3tdDD42VjMhm8ZoB8HpuOoXK5w=="],
|
||||||
|
|
||||||
|
"@typespec/ts-http-runtime": ["@typespec/ts-http-runtime@0.3.5", "", { "dependencies": { "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "tslib": "^2.6.2" } }, "sha512-yURCknZhvywvQItHMMmFSo+fq5arCUIyz/CVk7jD89MSai7dkaX8ufjCWp3NttLojoTVbcE72ri+be/TnEbMHw=="],
|
||||||
|
|
||||||
|
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
|
||||||
|
|
||||||
|
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
|
||||||
|
|
||||||
|
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||||
|
|
||||||
|
"brace-expansion": ["brace-expansion@1.1.13", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w=="],
|
||||||
|
|
||||||
"bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="],
|
"bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="],
|
||||||
|
|
||||||
|
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
||||||
|
|
||||||
|
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||||
|
|
||||||
|
"events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
|
||||||
|
|
||||||
|
"fast-xml-builder": ["fast-xml-builder@1.1.4", "", { "dependencies": { "path-expression-matcher": "^1.1.3" } }, "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg=="],
|
||||||
|
|
||||||
|
"fast-xml-parser": ["fast-xml-parser@5.5.11", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.4.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-QL0eb0YbSTVWF6tTf1+LEMSgtCEjBYPpnAjoLC8SscESlAjXEIRJ7cHtLG0pLeDFaZLa4VKZLArtA/60ZS7vyA=="],
|
||||||
|
|
||||||
|
"http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
|
||||||
|
|
||||||
|
"https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
|
||||||
|
|
||||||
|
"js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
|
||||||
|
|
||||||
|
"minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
|
||||||
|
|
||||||
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
"oxfmt": ["oxfmt@0.44.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.44.0", "@oxfmt/binding-android-arm64": "0.44.0", "@oxfmt/binding-darwin-arm64": "0.44.0", "@oxfmt/binding-darwin-x64": "0.44.0", "@oxfmt/binding-freebsd-x64": "0.44.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.44.0", "@oxfmt/binding-linux-arm-musleabihf": "0.44.0", "@oxfmt/binding-linux-arm64-gnu": "0.44.0", "@oxfmt/binding-linux-arm64-musl": "0.44.0", "@oxfmt/binding-linux-ppc64-gnu": "0.44.0", "@oxfmt/binding-linux-riscv64-gnu": "0.44.0", "@oxfmt/binding-linux-riscv64-musl": "0.44.0", "@oxfmt/binding-linux-s390x-gnu": "0.44.0", "@oxfmt/binding-linux-x64-gnu": "0.44.0", "@oxfmt/binding-linux-x64-musl": "0.44.0", "@oxfmt/binding-openharmony-arm64": "0.44.0", "@oxfmt/binding-win32-arm64-msvc": "0.44.0", "@oxfmt/binding-win32-ia32-msvc": "0.44.0", "@oxfmt/binding-win32-x64-msvc": "0.44.0" }, "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-lnncqvHewyRvaqdrnntVIrZV2tEddz8lbvPsQzG/zlkfvgZkwy0HP1p/2u1aCDToeg1jb9zBpbJdfkV73Itw+w=="],
|
"oxfmt": ["oxfmt@0.44.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.44.0", "@oxfmt/binding-android-arm64": "0.44.0", "@oxfmt/binding-darwin-arm64": "0.44.0", "@oxfmt/binding-darwin-x64": "0.44.0", "@oxfmt/binding-freebsd-x64": "0.44.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.44.0", "@oxfmt/binding-linux-arm-musleabihf": "0.44.0", "@oxfmt/binding-linux-arm64-gnu": "0.44.0", "@oxfmt/binding-linux-arm64-musl": "0.44.0", "@oxfmt/binding-linux-ppc64-gnu": "0.44.0", "@oxfmt/binding-linux-riscv64-gnu": "0.44.0", "@oxfmt/binding-linux-riscv64-musl": "0.44.0", "@oxfmt/binding-linux-s390x-gnu": "0.44.0", "@oxfmt/binding-linux-x64-gnu": "0.44.0", "@oxfmt/binding-linux-x64-musl": "0.44.0", "@oxfmt/binding-openharmony-arm64": "0.44.0", "@oxfmt/binding-win32-arm64-msvc": "0.44.0", "@oxfmt/binding-win32-ia32-msvc": "0.44.0", "@oxfmt/binding-win32-x64-msvc": "0.44.0" }, "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-lnncqvHewyRvaqdrnntVIrZV2tEddz8lbvPsQzG/zlkfvgZkwy0HP1p/2u1aCDToeg1jb9zBpbJdfkV73Itw+w=="],
|
||||||
|
|
||||||
"oxlint": ["oxlint@1.59.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.59.0", "@oxlint/binding-android-arm64": "1.59.0", "@oxlint/binding-darwin-arm64": "1.59.0", "@oxlint/binding-darwin-x64": "1.59.0", "@oxlint/binding-freebsd-x64": "1.59.0", "@oxlint/binding-linux-arm-gnueabihf": "1.59.0", "@oxlint/binding-linux-arm-musleabihf": "1.59.0", "@oxlint/binding-linux-arm64-gnu": "1.59.0", "@oxlint/binding-linux-arm64-musl": "1.59.0", "@oxlint/binding-linux-ppc64-gnu": "1.59.0", "@oxlint/binding-linux-riscv64-gnu": "1.59.0", "@oxlint/binding-linux-riscv64-musl": "1.59.0", "@oxlint/binding-linux-s390x-gnu": "1.59.0", "@oxlint/binding-linux-x64-gnu": "1.59.0", "@oxlint/binding-linux-x64-musl": "1.59.0", "@oxlint/binding-openharmony-arm64": "1.59.0", "@oxlint/binding-win32-arm64-msvc": "1.59.0", "@oxlint/binding-win32-ia32-msvc": "1.59.0", "@oxlint/binding-win32-x64-msvc": "1.59.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.18.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-0xBLeGGjP4vD9pygRo8iuOkOzEU1MqOnfiOl7KYezL/QvWL8NUg6n03zXc7ZVqltiOpUxBk2zgHI3PnRIEdAvw=="],
|
"oxlint": ["oxlint@1.59.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.59.0", "@oxlint/binding-android-arm64": "1.59.0", "@oxlint/binding-darwin-arm64": "1.59.0", "@oxlint/binding-darwin-x64": "1.59.0", "@oxlint/binding-freebsd-x64": "1.59.0", "@oxlint/binding-linux-arm-gnueabihf": "1.59.0", "@oxlint/binding-linux-arm-musleabihf": "1.59.0", "@oxlint/binding-linux-arm64-gnu": "1.59.0", "@oxlint/binding-linux-arm64-musl": "1.59.0", "@oxlint/binding-linux-ppc64-gnu": "1.59.0", "@oxlint/binding-linux-riscv64-gnu": "1.59.0", "@oxlint/binding-linux-riscv64-musl": "1.59.0", "@oxlint/binding-linux-s390x-gnu": "1.59.0", "@oxlint/binding-linux-x64-gnu": "1.59.0", "@oxlint/binding-linux-x64-musl": "1.59.0", "@oxlint/binding-openharmony-arm64": "1.59.0", "@oxlint/binding-win32-arm64-msvc": "1.59.0", "@oxlint/binding-win32-ia32-msvc": "1.59.0", "@oxlint/binding-win32-x64-msvc": "1.59.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.18.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-0xBLeGGjP4vD9pygRo8iuOkOzEU1MqOnfiOl7KYezL/QvWL8NUg6n03zXc7ZVqltiOpUxBk2zgHI3PnRIEdAvw=="],
|
||||||
|
|
||||||
"oxlint-tsgolint": ["oxlint-tsgolint@0.20.0", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "0.20.0", "@oxlint-tsgolint/darwin-x64": "0.20.0", "@oxlint-tsgolint/linux-arm64": "0.20.0", "@oxlint-tsgolint/linux-x64": "0.20.0", "@oxlint-tsgolint/win32-arm64": "0.20.0", "@oxlint-tsgolint/win32-x64": "0.20.0" }, "bin": { "tsgolint": "bin/tsgolint.js" } }, "sha512-/Uc9TQyN1l8w9QNvXtVHYtz+SzDJHKpb5X0UnHodl0BVzijUPk0LPlDOHAvogd1UI+iy9ZSF6gQxEqfzUxCULQ=="],
|
"oxlint-tsgolint": ["oxlint-tsgolint@0.20.0", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "0.20.0", "@oxlint-tsgolint/darwin-x64": "0.20.0", "@oxlint-tsgolint/linux-arm64": "0.20.0", "@oxlint-tsgolint/linux-x64": "0.20.0", "@oxlint-tsgolint/win32-arm64": "0.20.0", "@oxlint-tsgolint/win32-x64": "0.20.0" }, "bin": { "tsgolint": "bin/tsgolint.js" } }, "sha512-/Uc9TQyN1l8w9QNvXtVHYtz+SzDJHKpb5X0UnHodl0BVzijUPk0LPlDOHAvogd1UI+iy9ZSF6gQxEqfzUxCULQ=="],
|
||||||
|
|
||||||
|
"path-expression-matcher": ["path-expression-matcher@1.5.0", "", {}, "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ=="],
|
||||||
|
|
||||||
"semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
"semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
||||||
|
|
||||||
|
"strnum": ["strnum@2.2.3", "", {}, "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg=="],
|
||||||
|
|
||||||
"tinypool": ["tinypool@2.1.0", "", {}, "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw=="],
|
"tinypool": ["tinypool@2.1.0", "", {}, "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw=="],
|
||||||
|
|
||||||
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
"tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="],
|
"tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="],
|
||||||
|
|
||||||
"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@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||||
|
|
||||||
|
"bun-types/@types/node": ["@types/node@20.19.37", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw=="],
|
||||||
|
|
||||||
|
"bun-types/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
94560
dist/main.js
vendored
Normal file
94560
dist/main.js
vendored
Normal file
File diff suppressed because one or more lines are too long
73430
dist/post.js
vendored
Normal file
73430
dist/post.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -37,6 +37,21 @@ To pin a specific CLI version:
|
|||||||
version: 2.84.2
|
version: 2.84.2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To cache the Docker images pulled by `supabase start`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: supabase/setup-cli@v2
|
||||||
|
with:
|
||||||
|
version: 2.84.2
|
||||||
|
cache: true
|
||||||
|
- run: supabase start
|
||||||
|
```
|
||||||
|
|
||||||
|
The first run pulls the images from the registry. Later runs can restore the
|
||||||
|
same image archive from the GitHub Actions cache before `supabase start` runs.
|
||||||
|
Use `cache-key` when your workflow flags or generated config change the image
|
||||||
|
set.
|
||||||
|
|
||||||
## Resources
|
## Resources
|
||||||
|
|
||||||
- **Source Code**: <https://github.com/supabase/setup-cli>
|
- **Source Code**: <https://github.com/supabase/setup-cli>
|
||||||
|
|||||||
17
package.json
17
package.json
@@ -14,22 +14,29 @@
|
|||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"all": "bun run format && bun run lint && bun run coverage",
|
"all": "bun run format && bun run lint && bun run coverage && bun run build",
|
||||||
"ci": "bun run format:check && bun run lint && bun run coverage",
|
"build": "bun build src/main.ts src/post.ts --target=node --format=esm --outdir=dist",
|
||||||
|
"ci": "bun run format:check && bun run lint && bun run coverage && bun run build",
|
||||||
"coverage": "bun test --coverage --coverage-reporter=text --coverage-reporter=lcov",
|
"coverage": "bun test --coverage --coverage-reporter=text --coverage-reporter=lcov",
|
||||||
"format": "bun x oxfmt --write . '!coverage/**'",
|
"format": "bun x oxfmt --write . '!coverage/**' '!dist/**'",
|
||||||
"format:check": "bun x oxfmt --check . '!coverage/**'",
|
"format:check": "bun x oxfmt --check . '!coverage/**' '!dist/**'",
|
||||||
"lint": "bun x oxlint --deny-warnings --type-aware --type-check --tsconfig tsconfig.json src",
|
"lint": "bun x oxlint --deny-warnings --type-aware --type-check --tsconfig tsconfig.json src",
|
||||||
"test": "bun test",
|
"test": "bun test",
|
||||||
"typecheck": "bun x tsgo -p tsconfig.json --noEmit"
|
"typecheck": "bun x tsgo -p tsconfig.json --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@actions/cache": "^6.0.0",
|
||||||
"@actions/core": "^3.0.0",
|
"@actions/core": "^3.0.0",
|
||||||
"@actions/tool-cache": "^4.0.0"
|
"@actions/tool-cache": "^4.0.0",
|
||||||
|
"js-yaml": "^4.1.1",
|
||||||
|
"semver": "^7.7.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/bun": "^1.0.10",
|
"@tsconfig/bun": "^1.0.10",
|
||||||
"@types/bun": "^1.3.11",
|
"@types/bun": "^1.3.11",
|
||||||
|
"@types/js-yaml": "^4.0.9",
|
||||||
|
"@types/node": "^24",
|
||||||
|
"@types/semver": "^7.7.1",
|
||||||
"@typescript/native-preview": "^7.0.0-dev.20260409.1",
|
"@typescript/native-preview": "^7.0.0-dev.20260409.1",
|
||||||
"oxfmt": "^0.44.0",
|
"oxfmt": "^0.44.0",
|
||||||
"oxlint": "^1.59.0",
|
"oxlint": "^1.59.0",
|
||||||
|
|||||||
168
src/cache.test.ts
Normal file
168
src/cache.test.ts
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||||
|
import os from "node:os";
|
||||||
|
import path from "node:path";
|
||||||
|
import { afterEach, expect, mock, spyOn, test } from "bun:test";
|
||||||
|
import * as cacheAction from "@actions/cache";
|
||||||
|
import * as core from "@actions/core";
|
||||||
|
import {
|
||||||
|
collectDockerImageRefs,
|
||||||
|
createDockerImageCacheKey,
|
||||||
|
restoreDockerImageCache,
|
||||||
|
saveDockerImageCache,
|
||||||
|
} from "./cache";
|
||||||
|
|
||||||
|
const originalRunnerTemp = process.env.RUNNER_TEMP;
|
||||||
|
const originalWorkspace = process.env.GITHUB_WORKSPACE;
|
||||||
|
const tempDirs = new Set<string>();
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
mock.restore();
|
||||||
|
process.env.RUNNER_TEMP = originalRunnerTemp;
|
||||||
|
process.env.GITHUB_WORKSPACE = originalWorkspace;
|
||||||
|
|
||||||
|
for (const dir of tempDirs) {
|
||||||
|
rmSync(dir, { force: true, recursive: true });
|
||||||
|
}
|
||||||
|
tempDirs.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
function createTempDir(prefix: string): string {
|
||||||
|
const dir = mkdtempSync(path.join(os.tmpdir(), prefix));
|
||||||
|
tempDirs.add(dir);
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
test("creates a docker image cache key from runner, version, registry, and config", () => {
|
||||||
|
const workspace = createTempDir("setup-cli-workspace-");
|
||||||
|
mkdirSync(path.join(workspace, "supabase"), { recursive: true });
|
||||||
|
writeFileSync(path.join(workspace, "supabase", "config.toml"), 'project_id = "test"\n');
|
||||||
|
process.env.GITHUB_WORKSPACE = workspace;
|
||||||
|
|
||||||
|
const key = createDockerImageCacheKey("supabase 2.84.2", "ghcr.io");
|
||||||
|
|
||||||
|
expect(key).toStartWith(`supabase-cli-containers-v1-${process.platform}-${process.arch}-`);
|
||||||
|
expect(key).toContain("supabase-2.84.2-ghcr.io-");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("collects images from labeled containers and Supabase image repositories", async () => {
|
||||||
|
const run = mock(async (_file: string, args: string[]) => {
|
||||||
|
if (args[0] === "ps") {
|
||||||
|
return {
|
||||||
|
stdout: "ghcr.io/supabase/postgres:15.8.1\ncustom/image:latest\n",
|
||||||
|
stderr: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
stdout:
|
||||||
|
"ghcr.io/supabase/studio:2026.04.08\npublic.ecr.aws/supabase/kong:2.8.1\nlibrary/postgres:16\n<none>:<none>\n",
|
||||||
|
stderr: "",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await collectDockerImageRefs(run)).toEqual([
|
||||||
|
"custom/image:latest",
|
||||||
|
"ghcr.io/supabase/postgres:15.8.1",
|
||||||
|
"ghcr.io/supabase/studio:2026.04.08",
|
||||||
|
"public.ecr.aws/supabase/kong:2.8.1",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("restore skips docker and cache calls when cache input is disabled", async () => {
|
||||||
|
const run = mock(async () => ({ stdout: "", stderr: "" }));
|
||||||
|
const restoreCache = spyOn(cacheAction, "restoreCache").mockImplementation(async () => undefined);
|
||||||
|
const spies = {
|
||||||
|
getBooleanInput: spyOn(core, "getBooleanInput").mockImplementation(() => false),
|
||||||
|
getInput: spyOn(core, "getInput").mockImplementation(() => ""),
|
||||||
|
setOutput: spyOn(core, "setOutput").mockImplementation(() => {}),
|
||||||
|
saveState: spyOn(core, "saveState").mockImplementation(() => {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
await restoreDockerImageCache("supabase 2.84.2", "ghcr.io", run);
|
||||||
|
|
||||||
|
expect(spies.setOutput).toHaveBeenCalledWith("cache-hit", "false");
|
||||||
|
expect(spies.saveState).toHaveBeenCalledWith("cache-enabled", "false");
|
||||||
|
expect(run).not.toHaveBeenCalled();
|
||||||
|
expect(restoreCache).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("restore loads a docker archive on exact cache hit", async () => {
|
||||||
|
const temp = createTempDir("setup-cli-runner-");
|
||||||
|
process.env.RUNNER_TEMP = temp;
|
||||||
|
const calls: string[][] = [];
|
||||||
|
const run = mock(async (_file: string, args: string[]) => {
|
||||||
|
calls.push(args);
|
||||||
|
return { stdout: "ok\n", stderr: "" };
|
||||||
|
});
|
||||||
|
const restoreCache = spyOn(cacheAction, "restoreCache").mockImplementation(
|
||||||
|
async (paths: string[], key: string) => {
|
||||||
|
writeFileSync(paths[0]!, "archive");
|
||||||
|
return key;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const spies = {
|
||||||
|
getBooleanInput: spyOn(core, "getBooleanInput").mockImplementation(() => true),
|
||||||
|
getInput: spyOn(core, "getInput").mockImplementation((name: string) =>
|
||||||
|
name === "cache-key" ? "cache-key" : "",
|
||||||
|
),
|
||||||
|
setOutput: spyOn(core, "setOutput").mockImplementation(() => {}),
|
||||||
|
saveState: spyOn(core, "saveState").mockImplementation(() => {}),
|
||||||
|
info: spyOn(core, "info").mockImplementation(() => {}),
|
||||||
|
warning: spyOn(core, "warning").mockImplementation(() => {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
await restoreDockerImageCache("supabase 2.84.2", "ghcr.io", run);
|
||||||
|
|
||||||
|
expect(restoreCache).toHaveBeenCalledWith(
|
||||||
|
[path.join(temp, "setup-supabase-cli", "supabase-cli-docker-images.tar")],
|
||||||
|
"cache-key",
|
||||||
|
);
|
||||||
|
expect(spies.setOutput).toHaveBeenCalledWith("cache-hit", "true");
|
||||||
|
expect(spies.saveState).toHaveBeenCalledWith("cache-hit", "true");
|
||||||
|
expect(calls).toContainEqual([
|
||||||
|
"load",
|
||||||
|
"-i",
|
||||||
|
path.join(temp, "setup-supabase-cli", "supabase-cli-docker-images.tar"),
|
||||||
|
]);
|
||||||
|
expect(spies.warning).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("post saves collected Supabase docker images", async () => {
|
||||||
|
const temp = createTempDir("setup-cli-runner-");
|
||||||
|
process.env.RUNNER_TEMP = temp;
|
||||||
|
const calls: string[][] = [];
|
||||||
|
const run = mock(async (_file: string, args: string[]) => {
|
||||||
|
calls.push(args);
|
||||||
|
if (args[0] === "ps") {
|
||||||
|
return { stdout: "ghcr.io/supabase/postgres:15.8.1\n", stderr: "" };
|
||||||
|
}
|
||||||
|
if (args[0] === "image") {
|
||||||
|
return { stdout: "ghcr.io/supabase/studio:2026.04.08\n", stderr: "" };
|
||||||
|
}
|
||||||
|
return { stdout: "ok\n", stderr: "" };
|
||||||
|
});
|
||||||
|
const saveCache = spyOn(cacheAction, "saveCache").mockImplementation(async () => 1);
|
||||||
|
const state = new Map([
|
||||||
|
["cache-enabled", "true"],
|
||||||
|
["cache-hit", "false"],
|
||||||
|
["cache-primary-key", "cache-key"],
|
||||||
|
["cache-archive-path", path.join(temp, "setup-supabase-cli", "supabase-cli-docker-images.tar")],
|
||||||
|
]);
|
||||||
|
spyOn(core, "getState").mockImplementation((name: string) => state.get(name) ?? "");
|
||||||
|
spyOn(core, "info").mockImplementation(() => {});
|
||||||
|
spyOn(core, "warning").mockImplementation(() => {});
|
||||||
|
|
||||||
|
await saveDockerImageCache(run);
|
||||||
|
|
||||||
|
expect(calls).toContainEqual([
|
||||||
|
"save",
|
||||||
|
"-o",
|
||||||
|
path.join(temp, "setup-supabase-cli", "supabase-cli-docker-images.tar"),
|
||||||
|
"ghcr.io/supabase/postgres:15.8.1",
|
||||||
|
"ghcr.io/supabase/studio:2026.04.08",
|
||||||
|
]);
|
||||||
|
expect(saveCache).toHaveBeenCalledWith(
|
||||||
|
[path.join(temp, "setup-supabase-cli", "supabase-cli-docker-images.tar")],
|
||||||
|
"cache-key",
|
||||||
|
);
|
||||||
|
});
|
||||||
254
src/cache.ts
Normal file
254
src/cache.ts
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
import * as cache from "@actions/cache";
|
||||||
|
import * as core from "@actions/core";
|
||||||
|
import { execFile as execFileCallback } from "node:child_process";
|
||||||
|
import { createHash } from "node:crypto";
|
||||||
|
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
||||||
|
import os from "node:os";
|
||||||
|
import path from "node:path";
|
||||||
|
import { promisify } from "node:util";
|
||||||
|
|
||||||
|
const CLI_CONFIG_REGISTRY = "SUPABASE_INTERNAL_IMAGE_REGISTRY";
|
||||||
|
const CACHE_ARCHIVE = "supabase-cli-docker-images.tar";
|
||||||
|
const CACHE_DIR = "setup-supabase-cli";
|
||||||
|
const CACHE_KEY_VERSION = "v1";
|
||||||
|
const DEFAULT_REGISTRY = "public.ecr.aws";
|
||||||
|
const GHCR_REGISTRY = "ghcr.io";
|
||||||
|
const CACHE_INPUT = "cache";
|
||||||
|
const CACHE_KEY_INPUT = "cache-key";
|
||||||
|
const CACHE_HIT_OUTPUT = "cache-hit";
|
||||||
|
const STATE_ENABLED = "cache-enabled";
|
||||||
|
const STATE_PRIMARY_KEY = "cache-primary-key";
|
||||||
|
const STATE_ARCHIVE_PATH = "cache-archive-path";
|
||||||
|
const STATE_CACHE_HIT = "cache-hit";
|
||||||
|
const CLI_PROJECT_LABEL = "com.supabase.cli.project";
|
||||||
|
const SUPABASE_IMAGE_PREFIXES = ["ghcr.io/supabase/", "public.ecr.aws/supabase/", "supabase/"];
|
||||||
|
|
||||||
|
type ExecFile = (
|
||||||
|
file: string,
|
||||||
|
args: string[],
|
||||||
|
options?: { maxBuffer?: number },
|
||||||
|
) => Promise<{ stdout: string; stderr: string }>;
|
||||||
|
|
||||||
|
const execFile = promisify(execFileCallback) as ExecFile;
|
||||||
|
|
||||||
|
function sanitizeCacheKeyPart(value: string): string {
|
||||||
|
return value.replace(/[^A-Za-z0-9_.-]/g, "-").replace(/-+/g, "-");
|
||||||
|
}
|
||||||
|
|
||||||
|
function hashFile(filePath: string): string | null {
|
||||||
|
if (!existsSync(filePath)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return createHash("sha256").update(readFileSync(filePath)).digest("hex");
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getConfigHash(): string {
|
||||||
|
const workspaceRoot = process.env.GITHUB_WORKSPACE?.trim();
|
||||||
|
if (!workspaceRoot) {
|
||||||
|
return "no-config";
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashFile(path.join(workspaceRoot, "supabase", "config.toml")) ?? "no-config";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCacheArchivePath(): string {
|
||||||
|
const runnerTemp = process.env.RUNNER_TEMP?.trim() || os.tmpdir();
|
||||||
|
return path.join(runnerTemp, CACHE_DIR, CACHE_ARCHIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getImageRegistry(): string {
|
||||||
|
return process.env[CLI_CONFIG_REGISTRY]?.trim() || DEFAULT_REGISTRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getGhcrImageRegistry(): string {
|
||||||
|
return GHCR_REGISTRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createDockerImageCacheKey(installedVersion: string, registry: string): string {
|
||||||
|
return [
|
||||||
|
"supabase-cli-containers",
|
||||||
|
CACHE_KEY_VERSION,
|
||||||
|
sanitizeCacheKeyPart(process.platform),
|
||||||
|
sanitizeCacheKeyPart(process.arch),
|
||||||
|
sanitizeCacheKeyPart(installedVersion),
|
||||||
|
sanitizeCacheKeyPart(registry),
|
||||||
|
getConfigHash(),
|
||||||
|
].join("-");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPrimaryCacheKey(installedVersion: string, registry: string): string {
|
||||||
|
const cacheKeyInput = core.getInput(CACHE_KEY_INPUT).trim();
|
||||||
|
if (cacheKeyInput) {
|
||||||
|
return cacheKeyInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createDockerImageCacheKey(installedVersion, registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function isDockerAvailable(run: ExecFile = execFile): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
await run("docker", ["version"]);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runDocker(args: string[], run: ExecFile = execFile): Promise<string> {
|
||||||
|
const { stdout } = await run("docker", args, { maxBuffer: 1024 * 1024 * 16 });
|
||||||
|
return stdout;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeImageRefs(output: string): string[] {
|
||||||
|
return output
|
||||||
|
.split(/\r?\n/)
|
||||||
|
.map((line) => line.trim())
|
||||||
|
.filter((line) => line.length > 0 && !line.includes("<none>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSupabaseImageRef(ref: string): boolean {
|
||||||
|
return SUPABASE_IMAGE_PREFIXES.some((prefix) => ref.startsWith(prefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function collectDockerImageRefs(run: ExecFile = execFile): Promise<string[]> {
|
||||||
|
const refs = new Set<string>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const output = await runDocker(
|
||||||
|
["ps", "-a", "--filter", `label=${CLI_PROJECT_LABEL}`, "--format", "{{.Image}}"],
|
||||||
|
run,
|
||||||
|
);
|
||||||
|
for (const ref of normalizeImageRefs(output)) {
|
||||||
|
refs.add(ref);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(
|
||||||
|
`Could not list Supabase CLI containers for Docker image cache: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const output = await runDocker(["image", "ls", "--format", "{{.Repository}}:{{.Tag}}"], run);
|
||||||
|
for (const ref of normalizeImageRefs(output).filter(isSupabaseImageRef)) {
|
||||||
|
refs.add(ref);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(
|
||||||
|
`Could not list Docker images for Supabase image cache: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...refs].sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function restoreDockerImageCache(
|
||||||
|
installedVersion: string,
|
||||||
|
registry: string,
|
||||||
|
run: ExecFile = execFile,
|
||||||
|
): Promise<void> {
|
||||||
|
const enabled = core.getBooleanInput(CACHE_INPUT);
|
||||||
|
core.setOutput(CACHE_HIT_OUTPUT, "false");
|
||||||
|
core.saveState(STATE_ENABLED, String(enabled));
|
||||||
|
|
||||||
|
if (!enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const archivePath = getCacheArchivePath();
|
||||||
|
const primaryKey = getPrimaryCacheKey(installedVersion, registry);
|
||||||
|
mkdirSync(path.dirname(archivePath), { recursive: true });
|
||||||
|
core.saveState(STATE_PRIMARY_KEY, primaryKey);
|
||||||
|
core.saveState(STATE_ARCHIVE_PATH, archivePath);
|
||||||
|
core.saveState(STATE_CACHE_HIT, "false");
|
||||||
|
|
||||||
|
if (!(await isDockerAvailable(run))) {
|
||||||
|
core.warning("Docker is not available. Skipping Supabase Docker image cache restore.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let matchedKey: string | undefined;
|
||||||
|
try {
|
||||||
|
matchedKey = await cache.restoreCache([archivePath], primaryKey);
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(
|
||||||
|
`Could not restore Supabase Docker image cache: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matchedKey) {
|
||||||
|
core.info("No Supabase Docker image cache found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cacheHit = matchedKey === primaryKey;
|
||||||
|
core.setOutput(CACHE_HIT_OUTPUT, String(cacheHit));
|
||||||
|
core.saveState(STATE_CACHE_HIT, String(cacheHit));
|
||||||
|
|
||||||
|
if (!existsSync(archivePath)) {
|
||||||
|
core.warning("Supabase Docker image cache was restored, but the archive is missing.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await runDocker(["load", "-i", archivePath], run);
|
||||||
|
core.info("Loaded Supabase Docker images from cache.");
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(
|
||||||
|
`Could not load Supabase Docker image cache: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveDockerImageCache(run: ExecFile = execFile): Promise<void> {
|
||||||
|
if (core.getState(STATE_ENABLED) !== "true") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (core.getState(STATE_CACHE_HIT) === "true") {
|
||||||
|
core.info("Supabase Docker image cache hit. Skipping cache save.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const primaryKey = core.getState(STATE_PRIMARY_KEY);
|
||||||
|
const archivePath = core.getState(STATE_ARCHIVE_PATH) || getCacheArchivePath();
|
||||||
|
if (!primaryKey) {
|
||||||
|
core.warning("Supabase Docker image cache key is missing. Skipping cache save.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await isDockerAvailable(run))) {
|
||||||
|
core.warning("Docker is not available. Skipping Supabase Docker image cache save.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageRefs = await collectDockerImageRefs(run);
|
||||||
|
if (imageRefs.length === 0) {
|
||||||
|
core.warning("No Supabase Docker images found to cache.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdirSync(path.dirname(archivePath), { recursive: true });
|
||||||
|
try {
|
||||||
|
await runDocker(["save", "-o", archivePath, ...imageRefs], run);
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(
|
||||||
|
`Could not create Supabase Docker image archive: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await cache.saveCache([archivePath], primaryKey);
|
||||||
|
core.info(`Saved ${imageRefs.length} Supabase Docker image(s) to cache.`);
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(
|
||||||
|
`Could not save Supabase Docker image cache: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -146,10 +146,16 @@ function createPackageLock(version: string): string {
|
|||||||
|
|
||||||
function createActionSpies(inputVersion: string, cliDir: string, expectedUrlFragment: string) {
|
function createActionSpies(inputVersion: string, cliDir: string, expectedUrlFragment: string) {
|
||||||
return {
|
return {
|
||||||
getInput: spyOn(core, "getInput").mockReturnValue(inputVersion),
|
getInput: spyOn(core, "getInput").mockImplementation((name: string) =>
|
||||||
|
name === "version" ? inputVersion : "",
|
||||||
|
),
|
||||||
|
getBooleanInput: spyOn(core, "getBooleanInput").mockImplementation(() => false),
|
||||||
setOutput: spyOn(core, "setOutput").mockImplementation(() => {}),
|
setOutput: spyOn(core, "setOutput").mockImplementation(() => {}),
|
||||||
addPath: spyOn(core, "addPath").mockImplementation(() => {}),
|
addPath: spyOn(core, "addPath").mockImplementation(() => {}),
|
||||||
exportVariable: spyOn(core, "exportVariable").mockImplementation(() => {}),
|
exportVariable: spyOn(core, "exportVariable").mockImplementation(() => {}),
|
||||||
|
saveState: spyOn(core, "saveState").mockImplementation(() => {}),
|
||||||
|
info: spyOn(core, "info").mockImplementation(() => {}),
|
||||||
|
warning: spyOn(core, "warning").mockImplementation(() => {}),
|
||||||
setFailed: spyOn(core, "setFailed").mockImplementation(() => {}),
|
setFailed: spyOn(core, "setFailed").mockImplementation(() => {}),
|
||||||
downloadTool: spyOn(tc, "downloadTool").mockImplementation(async (url: string) => {
|
downloadTool: spyOn(tc, "downloadTool").mockImplementation(async (url: string) => {
|
||||||
expect(url).toContain(expectedUrlFragment);
|
expect(url).toContain(expectedUrlFragment);
|
||||||
@@ -179,10 +185,16 @@ test("awaits the action entrypoint with omitted version and latest fallback", as
|
|||||||
finishDownload = () => resolve(path.join(os.tmpdir(), "supabase-cli.tar.gz"));
|
finishDownload = () => resolve(path.join(os.tmpdir(), "supabase-cli.tar.gz"));
|
||||||
});
|
});
|
||||||
const spies = {
|
const spies = {
|
||||||
getInput: spyOn(core, "getInput").mockReturnValue(""),
|
getInput: spyOn(core, "getInput").mockImplementation((name: string) =>
|
||||||
|
name === "version" ? "" : "",
|
||||||
|
),
|
||||||
|
getBooleanInput: spyOn(core, "getBooleanInput").mockImplementation(() => false),
|
||||||
setOutput: spyOn(core, "setOutput").mockImplementation(() => {}),
|
setOutput: spyOn(core, "setOutput").mockImplementation(() => {}),
|
||||||
addPath: spyOn(core, "addPath").mockImplementation(() => {}),
|
addPath: spyOn(core, "addPath").mockImplementation(() => {}),
|
||||||
exportVariable: spyOn(core, "exportVariable").mockImplementation(() => {}),
|
exportVariable: spyOn(core, "exportVariable").mockImplementation(() => {}),
|
||||||
|
saveState: spyOn(core, "saveState").mockImplementation(() => {}),
|
||||||
|
info: spyOn(core, "info").mockImplementation(() => {}),
|
||||||
|
warning: spyOn(core, "warning").mockImplementation(() => {}),
|
||||||
setFailed: spyOn(core, "setFailed").mockImplementation(() => {}),
|
setFailed: spyOn(core, "setFailed").mockImplementation(() => {}),
|
||||||
downloadTool: spyOn(tc, "downloadTool").mockImplementation(async (url: string) => {
|
downloadTool: spyOn(tc, "downloadTool").mockImplementation(async (url: string) => {
|
||||||
expect(url).toContain("/latest/download/");
|
expect(url).toContain("/latest/download/");
|
||||||
|
|||||||
34
src/main.ts
34
src/main.ts
@@ -1,13 +1,18 @@
|
|||||||
import { $, semver } from "bun";
|
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import * as tc from "@actions/tool-cache";
|
import * as tc from "@actions/tool-cache";
|
||||||
|
import { load as loadYaml } from "js-yaml";
|
||||||
|
import * as semver from "semver";
|
||||||
|
import { execFile as execFileCallback } from "node:child_process";
|
||||||
import { existsSync, readFileSync } from "node:fs";
|
import { existsSync, readFileSync } from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { promisify } from "node:util";
|
||||||
|
import { getGhcrImageRegistry, getImageRegistry, restoreDockerImageCache } from "./cache";
|
||||||
|
|
||||||
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 DEFAULT_VERSION = "latest";
|
const DEFAULT_VERSION = "latest";
|
||||||
|
const execFile = promisify(execFileCallback);
|
||||||
|
|
||||||
type BunLock = {
|
type BunLock = {
|
||||||
workspaces?: {
|
workspaces?: {
|
||||||
@@ -106,7 +111,7 @@ function detectVersionFromPnpmLock(workspaceRoot: string): string | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const lockfile = Bun.YAML.parse(text) as PnpmLock;
|
const lockfile = loadYaml(text) as PnpmLock;
|
||||||
const rootImporter = lockfile.importers?.["."];
|
const rootImporter = lockfile.importers?.["."];
|
||||||
const dependency =
|
const dependency =
|
||||||
rootImporter?.dependencies?.supabase ?? rootImporter?.devDependencies?.supabase;
|
rootImporter?.dependencies?.supabase ?? rootImporter?.devDependencies?.supabase;
|
||||||
@@ -170,15 +175,30 @@ export function getDownloadUrl(version: string): string {
|
|||||||
return `https://github.com/supabase/cli/releases/latest/download/${filename}`;
|
return `https://github.com/supabase/cli/releases/latest/download/${filename}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (semver.order(version, REGISTRY_VERSION) === -1) {
|
if (semver.compare(version, REGISTRY_VERSION) === -1) {
|
||||||
return `https://github.com/supabase/cli/releases/download/v${version}/supabase_${version}_${platform}_${arch}.tar.gz`;
|
return `https://github.com/supabase/cli/releases/download/v${version}/supabase_${version}_${platform}_${arch}.tar.gz`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `https://github.com/supabase/cli/releases/download/v${version}/${filename}`;
|
return `https://github.com/supabase/cli/releases/download/v${version}/${filename}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSupabaseExecutable(cliPath: string): string {
|
||||||
|
const names =
|
||||||
|
process.platform === "win32" ? ["supabase.exe", "supabase.cmd", "supabase"] : ["supabase"];
|
||||||
|
|
||||||
|
for (const name of names) {
|
||||||
|
const executable = path.join(cliPath, name);
|
||||||
|
if (existsSync(executable)) {
|
||||||
|
return executable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.join(cliPath, "supabase");
|
||||||
|
}
|
||||||
|
|
||||||
export async function determineInstalledVersion(cliPath: string): Promise<string> {
|
export async function determineInstalledVersion(cliPath: string): Promise<string> {
|
||||||
const version = (await $`${path.join(cliPath, "supabase")} --version`.text()).trim();
|
const { stdout } = await execFile(getSupabaseExecutable(cliPath), ["--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");
|
||||||
}
|
}
|
||||||
@@ -195,9 +215,11 @@ export async function run(): Promise<void> {
|
|||||||
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 (version.toLowerCase() === "latest" || semver.compare(version, REGISTRY_VERSION) >= 0) {
|
||||||
core.exportVariable(CLI_CONFIG_REGISTRY, "ghcr.io");
|
core.exportVariable(CLI_CONFIG_REGISTRY, getGhcrImageRegistry());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await restoreDockerImageCache(installedVersion, getImageRegistry());
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(error instanceof Error ? error.message : String(error));
|
core.setFailed(error instanceof Error ? error.message : String(error));
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/post.ts
Normal file
17
src/post.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import * as core from "@actions/core";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { saveDockerImageCache } from "./cache";
|
||||||
|
|
||||||
|
export async function run(): Promise<void> {
|
||||||
|
try {
|
||||||
|
await saveDockerImageCache();
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(
|
||||||
|
`Supabase Docker image cache post step failed: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
||||||
|
await run();
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": "@tsconfig/bun/tsconfig.json",
|
"extends": "@tsconfig/bun/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"types": ["bun", "node"]
|
||||||
|
},
|
||||||
"include": ["src"]
|
"include": ["src"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user