189 lines · 7.3 KB · TypeScript
RawDownload
#!/usr/bin/env bunimport { $ } from "bun"import pkg from "../package.json"import { Script } from "@synsci/script"import { fileURLToPath } from "url" const dir = fileURLToPath(new URL("..", import.meta.url))process.chdir(dir) const binaries: Record<string, string> = {}for (const filepath of new Bun.Glob("@synsci/*/package.json").scanSync({ cwd: "./dist" })) {  const platform = await Bun.file(`./dist/${filepath}`).json()  // never let the meta package list itself (re-runs re-glob the dist dir)  if (platform.name === pkg.name) continue  binaries[platform.name] = platform.version}console.log("binaries", binaries)if (Object.keys(binaries).length === 0) {  throw new Error("No binary packages found in dist/. Did the build step run?")}const version = Object.values(binaries)[0] await $`mkdir -p ./dist/${pkg.name}`await $`cp -r ./bin ./dist/${pkg.name}/bin`await $`cp ./script/preinstall.mjs ./dist/${pkg.name}/preinstall.mjs`await $`cp ./script/postinstall.mjs ./dist/${pkg.name}/postinstall.mjs` await Bun.file(`./dist/${pkg.name}/package.json`).write(  JSON.stringify(    {      name: pkg.name,      bin: {        openscience: `./bin/openscience`,      },      scripts: {        // best-effort: clears a stale global @synsci/cli whose `openscience`        // bin link would make npm refuse the install (EEXIST); never fails        preinstall: "node ./preinstall.mjs || exit 0",        postinstall: "bun ./postinstall.mjs || node ./postinstall.mjs",      },      version: version,      // npm provenance refuses packages whose repository.url doesn't match      // the repo the workflow ran from (case-sensitive)      repository: {        type: "git",        url: "git+https://github.com/synthetic-sciences/openscience.git",      },      optionalDependencies: binaries,    },    null,    2,  ),) // Publish platform packages SEQUENTIALLY with retries. Each tarball is ~90MB;// publishing all 11 in parallel saturates the uplink and npm times out.const results: PromiseSettledResult<string>[] = []for (const [name] of Object.entries(binaries)) {  try {    if (!name.includes("windows")) {      await $`chmod 755 ./dist/${name}/bin/openscience`    }    await $`bun pm pack`.cwd(`./dist/${name}`)    let published = false    let lastErr: unknown    for (let attempt = 1; attempt <= 5 && !published; attempt++) {      try {        await $`npm publish *.tgz --access public --tag ${Script.channel}`.cwd(`./dist/${name}`)        published = true      } catch (e) {        lastErr = e        const msg = e instanceof Error ? e.message : String(e)        if (msg.includes("cannot publish over") || msg.includes("previously published")) {          published = true // already on the registry          break        }        console.warn(`  retry ${name} (attempt ${attempt})`)      }    }    if (!published) throw lastErr    console.log(`  published ${name}`)    results.push({ status: "fulfilled", value: name })  } catch (e) {    results.push({ status: "rejected", reason: e })  }}const failed = results.filter((r) => r.status === "rejected")const succeeded = results.filter((r) => r.status === "fulfilled")if (failed.length > 0) {  console.error(`${failed.length}/${results.length} binary packages failed to publish:`)  for (const f of failed) console.error("  ", (f as PromiseRejectedResult).reason)  throw new Error("Refusing to publish @synsci/openscience wrapper because one or more platform packages failed")}if (succeeded.length > 0) {  console.log(`${succeeded.length}/${results.length} binary packages published successfully`)}await $`cd ./dist/${pkg.name} && bun pm pack && npm publish *.tgz --access public --tag ${Script.channel}` // registries (Homebrew tap, AUR) — non-fatal, npm publish above is what mattersif (!Script.preview) {  try {    // Calculate SHA values    const arm64Sha = await $`sha256sum ./dist/openscience-linux-arm64.tar.gz | cut -d' ' -f1`      .text()      .then((x) => x.trim())    const x64Sha = await $`sha256sum ./dist/openscience-linux-x64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim())    const macX64Sha = await $`sha256sum ./dist/openscience-darwin-x64.zip | cut -d' ' -f1`.text().then((x) => x.trim())    const macArm64Sha = await $`sha256sum ./dist/openscience-darwin-arm64.zip | cut -d' ' -f1`      .text()      .then((x) => x.trim())     const [pkgver, _subver = ""] = Script.version.split(/(-.*)/, 2)     // Homebrew formula    const homebrewFormula = [      "# typed: false",      "# frozen_string_literal: true",      "",      "# This file was generated by GoReleaser. DO NOT EDIT.",      "class Openscience < Formula",      `  desc "The AI research agent built for the terminal."`,      `  homepage "https://github.com/synthetic-sciences/OpenScience"`,      `  version "${Script.version.split("-")[0]}"`,      "",      `  depends_on "ripgrep"`,      "",      "  on_macos do",      "    if Hardware::CPU.intel?",      `      url "https://github.com/synthetic-sciences/OpenScience/releases/download/v${Script.version}/openscience-darwin-x64.zip"`,      `      sha256 "${macX64Sha}"`,      "",      "      def install",      '        bin.install "openscience"',      "      end",      "    end",      "    if Hardware::CPU.arm?",      `      url "https://github.com/synthetic-sciences/OpenScience/releases/download/v${Script.version}/openscience-darwin-arm64.zip"`,      `      sha256 "${macArm64Sha}"`,      "",      "      def install",      '        bin.install "openscience"',      "      end",      "    end",      "  end",      "",      "  on_linux do",      "    if Hardware::CPU.intel? and Hardware::CPU.is_64_bit?",      `      url "https://github.com/synthetic-sciences/OpenScience/releases/download/v${Script.version}/openscience-linux-x64.tar.gz"`,      `      sha256 "${x64Sha}"`,      "      def install",      '        bin.install "openscience"',      "      end",      "    end",      "    if Hardware::CPU.arm? and Hardware::CPU.is_64_bit?",      `      url "https://github.com/synthetic-sciences/OpenScience/releases/download/v${Script.version}/openscience-linux-arm64.tar.gz"`,      `      sha256 "${arm64Sha}"`,      "      def install",      '        bin.install "openscience"',      "      end",      "    end",      "  end",      "end",      "",      "",    ].join("\n")     // The workflow's github.token is scoped to this repo and can never push    // to the tap repo — a dedicated fine-grained PAT is required.    const token = process.env.HOMEBREW_TAP_TOKEN    if (!token) {      console.warn(        "::warning title=homebrew skipped::HOMEBREW_TAP_TOKEN not set — brew users stay on the previous version",      )    } else {      const tap = `https://x-access-token:${token}@github.com/synthetic-sciences/homebrew-tap.git`      await $`rm -rf ./dist/homebrew-tap`      await $`git clone ${tap} ./dist/homebrew-tap`      await Bun.file("./dist/homebrew-tap/openscience.rb").write(homebrewFormula)      await $`cd ./dist/homebrew-tap && git add openscience.rb`      await $`cd ./dist/homebrew-tap && git commit -m "Update to v${Script.version}"`      await $`cd ./dist/homebrew-tap && git push`    }  } catch (e) {    const message = e instanceof Error ? e.message : String(e)    console.warn(      `::warning title=homebrew failed::tap update failed — brew users stay on the previous version (${message})`,    )  }}