diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml index fc78a6a..5b3873c 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -7,6 +7,7 @@ on: branches: - main workflow_dispatch: + jobs: setup-bun: runs-on: ${{ matrix.os }} @@ -25,17 +26,21 @@ jobs: - id: checkout name: Checkout uses: actions/checkout@v3 + - id: setup-bun name: Setup Bun uses: ./ with: bun-version: ${{ matrix.bun-version }} + - id: verify-bun name: Verify Bun run: | bun --version + setup-bun-from-package-json-version: runs-on: ${{ matrix.os }} + needs: setup-bun strategy: matrix: os: @@ -44,11 +49,26 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + - name: Setup package.json run: | echo "$(jq '. += {"packageManager": "bun@1.0.0"}' package.json)" > package.json + - name: Setup Bun uses: ./ + - name: Verify Bun run: | bun --version + + tests: + name: Run tests + needs: setup-bun + runs-on: 'ubuntu-latest' + + steps: + - name: Setup Bun + uses: ./ + + - name: Run tests + run: bun test --coverage diff --git a/README.md b/README.md index f224eff..1f5f2ec 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,19 @@ Download, install, and setup [Bun](https://bun.sh) in GitHub Actions. ## Usage ```yaml -- uses: oven-sh/setup-bun@v1 +- uses: oven-sh/setup-bun@v1.1.1 with: bun-version: latest ``` ### Setup custom registry-url and scope (for private packages) +For better DX and not having to expose the Github Token locally and inside repo commits, it would be wise to remove any `[install.scopes]` from a local `bunfig.toml` and move it to a global config file, that way each developer will have it's own file, it's not exposed to the repo and it also makes sure that each developer can manage the expiration date. + +[About global config](https://bun.sh/docs/runtime/bunfig#global-vs-local) + ```yaml -- uses: oven-sh/setup-bun@v1 +- uses: oven-sh/setup-bun@main # Or release version greater than v1 with: registry-url: "https://npm.pkg.github.com/" scope: "@foo-bar" diff --git a/bun.lockb b/bun.lockb index 34e7699..2887551 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/dist/action.js b/dist/action.js index f52f149..fb07aa7 100644 --- a/dist/action.js +++ b/dist/action.js @@ -78395,18 +78395,27 @@ function writeRegistryToConfigFile({ scope = scope.toLocaleLowerCase(); } core.info(`Setting auth in ${fileLocation}`); + const bunRegistryString = `'${scope}' = { token = "$BUN_AUTH_TOKEN", url = "${registryUrl}" }`; let newContents = ""; if ((0, import_node_fs.existsSync)(fileLocation)) { const curContents = (0, import_node_fs.readFileSync)(fileLocation, "utf8"); - curContents.split(import_node_os.EOL).forEach((line) => { - if (!line.toLowerCase().startsWith(scope)) { + const contents = curContents.split(import_node_os.EOL); + contents.forEach((line, index, array) => { + if (index > 0 && array[index - 1].includes("[install.scopes]")) { + newContents += bunRegistryString + import_node_os.EOL; + } + if (!line.toLowerCase().includes(scope)) { newContents += line + import_node_os.EOL; } }); + if (!contents.includes("[install.scopes]")) { + newContents += `[install.scopes]${import_node_os.EOL}${import_node_os.EOL}${bunRegistryString}${import_node_os.EOL}`; + } newContents += import_node_os.EOL; } - const bunRegistryString = `'${scope}' = { token = "$BUN_AUTH_TOKEN", url = "${registryUrl}"}`; - newContents += `[install.scopes]${import_node_os.EOL}${import_node_os.EOL}${bunRegistryString}${import_node_os.EOL}`; + if (!(0, import_node_fs.existsSync)(fileLocation)) { + newContents += `[install.scopes]${import_node_os.EOL}${import_node_os.EOL}${bunRegistryString}${import_node_os.EOL}`; + } (0, import_node_fs.writeFileSync)("./bunfig.toml", newContents); } diff --git a/package.json b/package.json index c052e2d..2321792 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "setup-bun", - "version": "1.0.0", + "version": "1.1.1", "description": "Setup Bun on GitHub Actions.", "keywords": [ "bun", @@ -31,6 +31,7 @@ }, "devDependencies": { "@types/node": "^20.8.2", + "bun-types": "latest", "esbuild": "^0.19.2", "prettier": "^2.8.4", "typescript": "^4.9.5" diff --git a/src/auth.spec.ts b/src/auth.spec.ts new file mode 100644 index 0000000..bb2b694 --- /dev/null +++ b/src/auth.spec.ts @@ -0,0 +1,139 @@ +import { afterEach, describe, expect, it } from "bun:test"; +import { unlink } from "fs"; +import { configureAuthentication } from "./auth"; +import { EOL } from "os"; + +describe("#configureAuthentication", () => { + const filePath = "bunfig.toml"; + + async function getFileAndContents() { + const file = Bun.file(filePath); + const contents = (await file.text()).split(EOL); + + return { file, contents }; + } + + afterEach(() => { + unlink(filePath, () => console.log(`${filePath} was deleted`)); + }); + + describe("when no bunfig.toml file exists", () => { + it("should create a new file with scopes content", async () => { + configureAuthentication("https://npm.pkg.github.com", "foo-bar"); + + const { file, contents } = await getFileAndContents(); + + expect(file.exists()).resolves.toBeTrue(); + + const expectedContents = [ + "[install.scopes]", + "", + '\'@foo-bar\' = { token = "$BUN_AUTH_TOKEN", url = "https://npm.pkg.github.com/" }', + "", + ]; + + contents.forEach((content, index) => + expect(content).toBe(expectedContents[index]) + ); + + expect(contents.length).toBe(expectedContents.length); + }); + }); + + describe("when local bunfig.toml file exists", () => { + it("and no [install.scopes] exists, should concatenate file correctly", async () => { + const bunfig = `[install]${EOL}optional = true${EOL}${EOL}[install.cache]${EOL}disable = true`; + + await Bun.write(filePath, bunfig); + + configureAuthentication("https://npm.pkg.github.com/", "foo-bar"); + + const { file, contents } = await getFileAndContents(); + + expect(file.exists()).resolves.toBeTrue(); + + const expectedContents = [ + "[install]", + "optional = true", + "", + "[install.cache]", + "disable = true", + "[install.scopes]", + "", + '\'@foo-bar\' = { token = "$BUN_AUTH_TOKEN", url = "https://npm.pkg.github.com/" }', + "", + "", + ]; + + contents.forEach((content, index) => + expect(content).toBe(expectedContents[index]) + ); + + expect(contents.length).toBe(expectedContents.length); + }); + + it("and [install.scopes] exists and it's not the same registry, should concatenate file correctly", async () => { + const bunfig = `[install]${EOL}optional = true${EOL}${EOL}[install.scopes]${EOL}'@bla-ble' = { token = "$BUN_AUTH_TOKEN", url = "https://npm.pkg.github.com/" }${EOL}${EOL}[install.cache]${EOL}disable = true`; + + await Bun.write(filePath, bunfig); + + configureAuthentication("https://npm.pkg.github.com/", "foo-bar"); + + const { file, contents } = await getFileAndContents(); + + expect(file.exists()).resolves.toBeTrue(); + + const expectedContents = [ + "[install]", + "optional = true", + "", + "[install.scopes]", + '\'@foo-bar\' = { token = "$BUN_AUTH_TOKEN", url = "https://npm.pkg.github.com/" }', + '\'@bla-ble\' = { token = "$BUN_AUTH_TOKEN", url = "https://npm.pkg.github.com/" }', + "", + "[install.cache]", + "disable = true", + "", + "", + ]; + + contents.forEach((content, index) => + expect(content).toBe(expectedContents[index]) + ); + + expect(contents.length).toBe(expectedContents.length); + }); + + it("and [install.scopes] exists and it's the same registry, should concatenate file correctly", async () => { + const bunfig = `[install]${EOL}optional = true${EOL}${EOL}[install.scopes]${EOL}'@foo-bar' = { token = "$BUN_AUTH_TOKEN", url = "https://npm.pkg.github.com/" }${EOL}'@bla-ble' = { token = "$BUN_AUTH_TOKEN", url = "https://npm.pkg.github.com/" }${EOL}${EOL}[install.cache]${EOL}disable = true`; + + await Bun.write(filePath, bunfig); + + configureAuthentication("https://npm.pkg.github.com/", "foo-bar"); + + const { file, contents } = await getFileAndContents(); + + expect(file.exists()).resolves.toBeTrue(); + + const expectedContents = [ + "[install]", + "optional = true", + "", + "[install.scopes]", + '\'@foo-bar\' = { token = "$BUN_AUTH_TOKEN", url = "https://npm.pkg.github.com/" }', + '\'@bla-ble\' = { token = "$BUN_AUTH_TOKEN", url = "https://npm.pkg.github.com/" }', + "", + "[install.cache]", + "disable = true", + "", + "", + ]; + + contents.forEach((content, index) => + expect(content).toBe(expectedContents[index]) + ); + + expect(contents.length).toBe(expectedContents.length); + }); + }); +}); diff --git a/src/auth.ts b/src/auth.ts index e635bfe..54ca063 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -34,24 +34,37 @@ function writeRegistryToConfigFile({ core.info(`Setting auth in ${fileLocation}`); + const bunRegistryString = `'${scope}' = { token = "$BUN_AUTH_TOKEN", url = "${registryUrl}" }`; let newContents = ""; if (existsSync(fileLocation)) { const curContents = readFileSync(fileLocation, "utf8"); - curContents.split(EOL).forEach((line: string) => { - // Add current contents unless they are setting the registry - if (!line.toLowerCase().startsWith(scope)) { + const contents = curContents.split(EOL); + + contents.forEach((line, index, array) => { + // If last item is [install.scopes], than it should add the action scope + registry + if (index > 0 && array[index - 1].includes('[install.scopes]')) { + newContents += bunRegistryString + EOL; + } + + // Only add the line if scope does not exists + if (!line.toLowerCase().includes(scope)) { newContents += line + EOL; } }); + // In case bunfig.toml has other properties and does not have [install.scopes] + if (!contents.includes('[install.scopes]')) { + newContents += `[install.scopes]${EOL}${EOL}${bunRegistryString}${EOL}` + } + newContents += EOL; } - const bunRegistryString = `'${scope}' = { token = "$BUN_AUTH_TOKEN", url = "${registryUrl}"}`; - - newContents += `[install.scopes]${EOL}${EOL}${bunRegistryString}${EOL}`; + if (!existsSync(fileLocation)) { + newContents += `[install.scopes]${EOL}${EOL}${bunRegistryString}${EOL}` + } writeFileSync("./bunfig.toml", newContents); } diff --git a/tsconfig.json b/tsconfig.json index 2dfdb6e..5493748 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,7 @@ "module": "ES2020", "target": "ES2020", "moduleResolution": "node", - "skipLibCheck": true + "skipLibCheck": true, + "types": ["bun-types"] } }