Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/danielroe/uppt. A composite GitHub Action that turns conventional commits into a draft release PR, tags the PR on merge, and stages publishing to npm via OIDC trusted publishing.
github-action npm npmjs oidc staged-publish trusted-publishing
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196import { mkdirSync, mkdtempSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'import { tmpdir } from 'node:os'import { resolve } from 'node:path'import process from 'node:process'import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
const execFileSync = vi.hoisted(() => vi.fn())vi.mock('node:child_process', () => ({ execFileSync }))
const { main } = await import('../scripts/pack.ts')
const PACK_ENV = ['GITHUB_REF', 'RELEASES', 'PACK_OUT_DIR', 'PACKAGES', 'GITHUB_OUTPUT', 'NIGHTLY', 'NIGHTLY_SUFFIX', 'NIGHTLY_ALIASES'] as const
let env: NodeJS.ProcessEnvlet cwd: stringlet root: stringlet outDir: string
function writePkg (dir: string, pkg: Record<string, unknown>) { mkdirSync(dir, { recursive: true }) writeFileSync(resolve(dir, 'package.json'), JSON.stringify(pkg))}
/** Make the mocked pack tool emit `filename` and drop a matching tarball in `outDir`. */function packsAs (...filenames: string[]) { let i = 0 execFileSync.mockImplementation(() => { const filename = filenames[Math.min(i++, filenames.length - 1)]! writeFileSync(resolve(outDir, filename), 'tarball') return `{"name":"pkg","filename":"${filename}"}\n` })}
beforeEach(() => { env = { ...process.env } cwd = process.cwd() for (const key of PACK_ENV) delete process.env[key] root = realpathSync(mkdtempSync(resolve(tmpdir(), 'uppt-pack-'))) outDir = resolve(root, 'out') process.env.PACK_OUT_DIR = outDir process.env.GITHUB_REF = 'refs/tags/v1.2.3' writePkg(root, { name: 'root-pkg', version: '1.2.3' }) process.chdir(root) vi.spyOn(console, 'log').mockImplementation(() => {})})
afterEach(() => { process.chdir(cwd) process.env = env execFileSync.mockReset() vi.restoreAllMocks()})
describe('pack', () => { it('rejects a ref that is not a semver tag', () => { process.env.GITHUB_REF = 'refs/heads/main' expect(() => main()).toThrow(/must be a strict-semver/) })
it('reports an unset ref', () => { delete process.env.GITHUB_REF expect(() => main()).toThrow(/got '<unset>'/) })
it('requires PACK_OUT_DIR', () => { delete process.env.PACK_OUT_DIR expect(() => main()).toThrow('PACK_OUT_DIR is required') })
it('packs the repo root with npm when there is no pnpm lockfile', () => { packsAs('root-pkg-1.2.3.tgz') main() expect(execFileSync).toHaveBeenCalledTimes(1) const [cmd, args] = execFileSync.mock.calls[0]! expect(cmd).toBe('npm') expect(args).toEqual(['pack', '--pack-destination', outDir, '--json', '--silent']) })
it('packs with pnpm when a pnpm lockfile is present', () => { writeFileSync(resolve(root, 'pnpm-lock.yaml'), '') packsAs('root-pkg-1.2.3.tgz') main() const [cmd, args] = execFileSync.mock.calls[0]! expect(cmd).toBe('pnpm') expect(args).toEqual(['pack', '--pack-destination', outDir, '--json']) })
it('packs each declared workspace', () => { writePkg(resolve(root, 'packages/a'), { name: 'a', version: '1.2.3' }) writePkg(resolve(root, 'packages/b'), { name: 'b', version: '1.2.3' }) process.env.PACKAGES = 'packages/*' packsAs('a-1.2.3.tgz', 'b-1.2.3.tgz') main() expect(execFileSync.mock.calls.map(call => call[2].cwd)).toEqual([ resolve(root, 'packages/a'), resolve(root, 'packages/b'), ]) })
it('writes the packed filenames to GITHUB_OUTPUT', () => { const outputFile = resolve(root, 'gh-output') writeFileSync(outputFile, '') process.env.GITHUB_OUTPUT = outputFile packsAs('root-pkg-1.2.3.tgz') main() expect(readFileSync(outputFile, 'utf8')).toBe('files=["root-pkg-1.2.3.tgz"]\n') })
it('throws when the pack tool reports a tarball it did not write', () => { execFileSync.mockReturnValue('{"name":"pkg","filename":"ghost-1.2.3.tgz"}\n') expect(() => main()).toThrow(/is not present in/) })
it('throws when two workspaces produce the same tarball name', () => { writePkg(resolve(root, 'packages/a'), { name: 'a', version: '1.2.3' }) writePkg(resolve(root, 'packages/b'), { name: 'b', version: '1.2.3' }) process.env.PACKAGES = 'packages/*' packsAs('a-1.2.3.tgz') expect(() => main()).toThrow(/duplicate tarball/) })
describe('independent mode', () => { beforeEach(() => { process.env.GITHUB_REF = 'refs/tags/release-2024-05-01' writePkg(resolve(root, 'packages/kit'), { name: '@nuxt/kit', version: '5.0.0' }) process.env.RELEASES = JSON.stringify([{ name: '@nuxt/kit', version: '5.0.0', dir: 'packages/kit' }]) })
it('packs exactly the dispatched workspaces', () => { packsAs('nuxt-kit-5.0.0.tgz') main() expect(execFileSync.mock.calls[0]![2].cwd).toBe(resolve(root, 'packages/kit')) })
it('requires a coordination tag', () => { process.env.GITHUB_REF = 'refs/tags/v1.2.3' expect(() => main()).toThrow(/coordination tag/) })
it('reports an unset ref', () => { delete process.env.GITHUB_REF expect(() => main()).toThrow(/got '<unset>'/) })
it('throws when an entry points at a directory with no package.json', () => { process.env.RELEASES = JSON.stringify([{ name: '@nuxt/kit', version: '5.0.0', dir: 'packages/gone' }]) expect(() => main()).toThrow(/has no package.json/) })
it('throws when an entry points at a private package', () => { writePkg(resolve(root, 'packages/kit'), { name: '@nuxt/kit', version: '5.0.0', private: true }) expect(() => main()).toThrow(/private package/) })
it('throws when an entry does not match the package.json on disk', () => { writePkg(resolve(root, 'packages/kit'), { name: '@nuxt/kit', version: '4.0.0' }) expect(() => main()).toThrow(/does not match/) }) })
describe('nightly mode', () => { beforeEach(() => { process.env.NIGHTLY = 'true' process.env.GITHUB_REF = 'refs/heads/main' })
it('rewrites the package before packing it', () => { process.env.NIGHTLY_SUFFIX = '-edge' process.env.NIGHTLY_ALIASES = 'nuxi' writePkg(root, { name: 'root-pkg', version: '1.2.3', dependencies: { nuxi: '^3' } }) const packed = vi.fn() execFileSync.mockImplementation((cmd: string) => { if (cmd === 'git') return '0123456789abcdef 1778749542' packed(JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'))) const filename = 'root-pkg-edge-1.2.3-2605140905-0123456.tgz' writeFileSync(resolve(outDir, filename), 'tarball') return `{"filename":"${filename}"}` }) main() expect(packed).toHaveBeenCalledWith({ name: 'root-pkg-edge', version: '1.2.3-2605140905-0123456', dependencies: { nuxi: 'npm:nuxi-edge@latest' } }) })
it('requires a branch ref', () => { process.env.GITHUB_REF = 'refs/tags/v1.2.3' expect(() => main()).toThrow(/must be a 'refs\/heads\/\*' branch/) delete process.env.GITHUB_REF expect(() => main()).toThrow(/got '<unset>'/) })
it('cannot be combined with RELEASES', () => { process.env.RELEASES = JSON.stringify([{ name: 'root-pkg', version: '1.2.3', dir: '.' }]) expect(() => main()).toThrow(/RELEASES cannot be combined with NIGHTLY/) }) })})