Files
setup-cli/__tests__/main.test.ts
Julien Goux ad077b4817 fix: v1 setup on Linux musl (#432)
## Summary

- Detect Linux musl runners in the v1 action and download the Supabase
CLI `.apk` asset for CLI versions `>= 2.99.0`.
- Add the extracted `usr/bin` directory to `PATH` for `.apk` archives.
- Backport the optional `github-token` input for authenticated `latest`
release lookup, because the test matrix hit unauthenticated GitHub API
rate limits.
- Rebuild `dist/index.js` for the Node action.

## Validation

- `npm run format:check`
- `npm run lint`
- `npm test`
- `npm run package`
- Local Docker smoke test in `node:20-alpine` with
`INPUT_VERSION=2.100.1`
- setup-cli-testing workflow:
https://github.com/jgoux/setup-cli-testing/actions/runs/26165593808

The external workflow passed Alpine `2.100.1`, Alpine `latest`, and
Ubuntu/macOS/Windows with both `2.100.1` and `latest`.
2026-05-20 16:22:46 +02:00

164 lines
5.1 KiB
TypeScript

import { getCliPath, getDownloadArchive, getDownloadUrl } from '../src/utils'
import { CLI_CONFIG_REGISTRY } from '../src/main'
import * as os from 'os'
import * as process from 'process'
import * as cp from 'child_process'
import * as path from 'path'
import * as fs from 'fs'
import * as yaml from 'js-yaml'
import * as url from 'url'
import { afterEach, expect, jest, test } from '@jest/globals'
afterEach(() => {
jest.restoreAllMocks()
})
test('gets download url to binary', async () => {
const url = await getDownloadUrl('1.28.0')
expect(
url.startsWith(
'https://github.com/supabase/cli/releases/download/v1.28.0/supabase_'
)
).toBeTruthy()
expect(url.endsWith('.tar.gz')).toBeTruthy()
expect(url).not.toContain('_1.28.0_')
})
test('gets legacy download url to binary', async () => {
const url = await getDownloadUrl('0.1.0')
expect(
url.startsWith(
`https://github.com/supabase/cli/releases/download/v0.1.0/supabase_0.1.0_`
)
).toBeTruthy()
expect(url.endsWith('.tar.gz')).toBeTruthy()
})
test('gets download url to latest version', async () => {
jest.spyOn(globalThis, 'fetch').mockResolvedValue(
new Response(JSON.stringify({ tag_name: 'v2.99.0' }), {
status: 200,
statusText: 'OK'
})
)
const url = await getDownloadUrl('latest')
expect(url).toContain('/download/v2.99.0/supabase_2.99.0_')
expect(url).toMatch(/\.tar\.gz$|\.zip$/)
})
test('authenticates latest version lookup when a GitHub token is provided', async () => {
const fetchMock = jest.spyOn(globalThis, 'fetch').mockResolvedValue(
new Response(JSON.stringify({ tag_name: 'v2.99.0' }), {
status: 200,
statusText: 'OK'
})
)
await getDownloadUrl('latest', 'github-token')
expect(fetchMock).toHaveBeenCalledWith(
'https://api.github.com/repos/supabase/cli/releases/latest',
expect.objectContaining({
headers: expect.objectContaining({
Accept: 'application/vnd.github+json',
Authorization: 'Bearer github-token',
'X-GitHub-Api-Version': '2022-11-28'
})
})
)
})
test('omits authorization from latest version lookup without a GitHub token', async () => {
const fetchMock = jest.spyOn(globalThis, 'fetch').mockResolvedValue(
new Response(JSON.stringify({ tag_name: 'v2.99.0' }), {
status: 200,
statusText: 'OK'
})
)
await getDownloadUrl('latest')
expect(fetchMock).toHaveBeenCalledWith(
'https://api.github.com/repos/supabase/cli/releases/latest',
expect.objectContaining({
headers: expect.not.objectContaining({
Authorization: expect.any(String)
})
})
)
})
test('gets versioned archive url to binary from Supabase CLI v2.99.0', async () => {
const archive = await getDownloadArchive('2.99.0', 'linux', 'x64')
expect(archive).toEqual({
url: 'https://github.com/supabase/cli/releases/download/v2.99.0/supabase_2.99.0_linux_amd64.tar.gz',
format: 'tar'
})
})
test('gets apk archive url on Linux musl from Supabase CLI v2.99.0', async () => {
const archive = await getDownloadArchive('2.99.0', 'linux', 'x64', true)
expect(archive).toEqual({
url: 'https://github.com/supabase/cli/releases/download/v2.99.0/supabase_2.99.0_linux_amd64.apk',
format: 'apk'
})
})
test('keeps tar archives before Supabase CLI v2.99.0 on Linux musl', async () => {
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', () => {
expect(getCliPath('/tmp/extracted', 'apk')).toBe('/tmp/extracted/usr/bin')
expect(getCliPath('/tmp/extracted', 'tar')).toBe('/tmp/extracted')
expect(getCliPath('/tmp/extracted', 'zip')).toBe('/tmp/extracted')
})
test('gets versioned zip archive url on Windows from Supabase CLI v2.99.0', async () => {
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('keeps unversioned archive url to binary before Supabase CLI v2.99.0', async () => {
const url = await getDownloadUrl('2.98.2')
expect(url).toContain('/download/v2.98.2/supabase_')
expect(url).not.toContain('supabase_2.98.2_')
expect(url).toMatch(/\.tar\.gz$/)
})
// shows how the runner will run a javascript action with env / stdout protocol
test('runs main action', () => {
const { env, execPath } = process
const repo = path.dirname(path.dirname(url.fileURLToPath(import.meta.url)))
const config = path.join(repo, 'action.yml')
const action = yaml.load(fs.readFileSync(config, 'utf8')) as {
inputs: { version: { default: string } }
}
const ip = path.join(repo, 'dist', 'index.js')
const stdout = cp
.execFileSync(execPath, [ip], {
env: {
...env,
RUNNER_TEMP: os.tmpdir(),
INPUT_VERSION: action.inputs.version.default
}
})
.toString()
expect
.stringContaining(`::set-env name=${CLI_CONFIG_REGISTRY}::`)
.asymmetricMatch(stdout)
})