diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7fd133ba..cbe04e06 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -116,3 +116,19 @@ jobs: env: GH_TOKEN: ${{ github.token }} run: gh release edit "${{ needs.create-release.outputs.tag }}" --draft=false --repo "${{ github.repository }}" + + # 4) Push the release out to the downstream package managers. + # + # This is a direct call, NOT submit-packages.yml's own `release: [published]` + # trigger. The un-draft above uses GITHUB_TOKEN, and GitHub raises no workflow + # events for what a GITHUB_TOKEN does, so that trigger never fired once in the + # three months it was wired up and no channel was ever updated past 0.1.0. + # Calling the workflow keeps that guarantee without needing a PAT. + distribute: + needs: [create-release, publish] + uses: ./.github/workflows/submit-packages.yml + secrets: inherit + with: + version: ${{ needs.create-release.outputs.version }} + dry_run: false + package_managers: all diff --git a/.github/workflows/submit-packages.yml b/.github/workflows/submit-packages.yml index 8a353f9f..1282da48 100644 --- a/.github/workflows/submit-packages.yml +++ b/.github/workflows/submit-packages.yml @@ -1,25 +1,46 @@ name: Submit to Package Managers -# Refresh + submit downstream package managers after a release. Mirrors -# pairux.com's submit-packages workflow but stays in this monorepo. Each channel -# is gated on its secret; without the secret it dry-runs (no-op), so this never -# fails for missing credentials. +# Refresh + submit downstream package managers after a release. Each channel is +# gated on its secret; without the secret it refreshes the manifest and skips the +# submit, so this never fails for missing credentials. +# +# NOT triggered by `release: [published]`. release.yml un-drafts with +# GITHUB_TOKEN, and GitHub deliberately raises no workflow events for anything a +# GITHUB_TOKEN does, so that trigger never fired once between 2026-06-25 and +# 2026-09-24 and every channel silently stayed on 0.1.0. release.yml now calls +# this workflow directly instead, which needs no PAT. on: - release: - types: [published] + workflow_call: + inputs: + version: + description: 'Version without v prefix (e.g. 0.1.0)' + required: true + type: string + dry_run: + description: 'Refresh manifests without submitting' + type: boolean + default: false + package_managers: + description: 'Comma-separated, or "all"' + type: string + default: all workflow_dispatch: inputs: version: description: 'Version without v prefix (e.g. 0.1.0)' required: true dry_run: - description: 'Generate manifests without submitting' + description: 'Refresh manifests without submitting' type: boolean default: true package_managers: description: 'Comma-separated, or "all"' default: all +permissions: + contents: write + pull-requests: write + jobs: # Everything except Chocolatey runs on Linux. submit-linux: @@ -31,50 +52,74 @@ jobs: - name: Resolve version id: v - run: | - if [ -n "${{ github.event.inputs.version }}" ]; then V="${{ github.event.inputs.version }}"; else V="${{ github.event.release.tag_name }}"; fi - echo "version=${V#v}" >> "$GITHUB_OUTPUT" + env: + V_IN: ${{ inputs.version }} + run: echo "version=${V_IN#v}" >> "$GITHUB_OUTPUT" - name: Resolve package managers id: pms + env: + PMS_IN: ${{ inputs.package_managers }} run: | - PMS="${{ github.event.inputs.package_managers }}" + PMS="$PMS_IN" [ -z "$PMS" ] && PMS="all" if [ "$PMS" = "all" ]; then PMS="homebrew,scoop,winget,aur,apt,rpm,gentoo,nix,snap,flatpak,appimage,freebsd"; fi echo "list=$(echo "$PMS" | sed 's/chocolatey,*//g')" >> "$GITHUB_OUTPUT" - name: Refresh + submit manifests env: - DRY_RUN: ${{ github.event.inputs.dry_run }} + # A release calls this with dry_run=false. This previously read + # github.event.inputs.dry_run, which is empty on anything but a + # workflow_dispatch, so the "!= false" test below appended --dry-run on + # every release run: the submit path could never have executed even if + # the trigger had worked. + DRY_RUN: ${{ inputs.dry_run }} GH_TOKEN: ${{ github.token }} AUR_SSH_KEY: ${{ secrets.AUR_SSH_KEY }} GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} + HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} + SCOOP_BUCKET_TOKEN: ${{ secrets.SCOOP_BUCKET_TOKEN }} + SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }} run: | ARGS="-v ${{ steps.v.outputs.version }}" for PM in $(echo "${{ steps.pms.outputs.list }}" | tr ',' ' '); do ARGS="$ARGS -p $PM"; done - # Default to dry-run unless explicitly disabled AND submit secrets exist. if [ "$DRY_RUN" != "false" ]; then ARGS="$ARGS --dry-run"; fi node scripts/submit-packages.mjs $ARGS + # The refreshed manifests are the input to every future submission, so they + # have to outlive the runner. Without this they were rewritten and thrown + # away, which is why distribution/ still said 0.1.0 at release 3.15.0. + - name: Open a PR with the refreshed manifests + if: ${{ inputs.dry_run != true }} + env: + GH_TOKEN: ${{ github.token }} + VERSION: ${{ steps.v.outputs.version }} + run: bash scripts/open-distribution-pr.sh + # Chocolatey publishes from Windows. submit-chocolatey: runs-on: windows-latest name: Submit (Chocolatey) if: >- - github.event.inputs.package_managers == 'all' || - github.event.inputs.package_managers == '' || - github.event_name == 'release' || - contains(github.event.inputs.package_managers, 'chocolatey') + inputs.package_managers == 'all' || + inputs.package_managers == '' || + contains(inputs.package_managers, 'chocolatey') steps: - uses: actions/checkout@v5 - name: Resolve version id: v shell: bash - run: | - if [ -n "${{ github.event.inputs.version }}" ]; then V="${{ github.event.inputs.version }}"; else V="${{ github.event.release.tag_name }}"; fi - echo "version=${V#v}" >> "$GITHUB_OUTPUT" - - name: Refresh chocolatey manifest + env: + V_IN: ${{ inputs.version }} + run: echo "version=${V_IN#v}" >> "$GITHUB_OUTPUT" + - name: Refresh + submit chocolatey manifest shell: bash env: + # Was hardcoded --dry-run, so chocolatey could never publish regardless + # of trigger or credentials. + DRY_RUN: ${{ inputs.dry_run }} CHOCOLATEY_API_KEY: ${{ secrets.CHOCOLATEY_API_KEY }} - run: node scripts/submit-packages.mjs -v ${{ steps.v.outputs.version }} -p chocolatey --dry-run + run: | + ARGS="-v ${{ steps.v.outputs.version }} -p chocolatey" + if [ "$DRY_RUN" != "false" ]; then ARGS="$ARGS --dry-run"; fi + node scripts/submit-packages.mjs $ARGS diff --git a/distribution/aur/PKGBUILD b/distribution/aur/PKGBUILD index c534fd1f..9200deac 100644 --- a/distribution/aur/PKGBUILD +++ b/distribution/aur/PKGBUILD @@ -1,7 +1,7 @@ # Maintainer: Profullstack, Inc. # AUR binary package — consumes the GitHub release tarball. pkgname=tronbrowser-bin -pkgver=0.1.0 +pkgver=3.15.0 pkgrel=1 pkgdesc="Open-source, privacy-first, AI-native browser (Ungoogled Chromium fork)" arch=('x86_64') @@ -11,7 +11,7 @@ depends=('chromium') provides=('tronbrowser') conflicts=('tronbrowser') source=("tronbrowser-${pkgver}.tar.gz::https://github.com/profullstack/tronbrowser.dev/releases/download/v${pkgver}/tronbrowser-linux-x64.tar.gz") -sha256sums=('d966a54a6369ec283203abd257f89e50844ff68551229a463f568dc638dcf4c7') +sha256sums=('0870fc5fd4b7acdfa1679f542d038a34e932b65721918cb4c1071e7a6b008779') package() { install -dm755 "${pkgdir}/usr/lib/tronbrowser" diff --git a/distribution/homebrew/tronbrowser.rb b/distribution/homebrew/tronbrowser.rb index 93f73952..1bdb2a67 100644 --- a/distribution/homebrew/tronbrowser.rb +++ b/distribution/homebrew/tronbrowser.rb @@ -4,17 +4,17 @@ class Tronbrowser < Formula desc "Open-source, privacy-first, AI-native browser (Ungoogled Chromium fork)" homepage "https://tronbrowser.dev" - version "0.1.0" + version "3.15.0" license "MIT" on_macos do - url "https://github.com/profullstack/tronbrowser.dev/releases/download/v0.1.0/tronbrowser-macos.zip" + url "https://github.com/profullstack/tronbrowser.dev/releases/download/v3.15.0/tronbrowser-macos.zip" sha256 "4f928b90b83a34d90edf6f3b4f522c47b85090046424ce69cc535a0cb85d77d1" end on_linux do - url "https://github.com/profullstack/tronbrowser.dev/releases/download/v0.1.0/tronbrowser-linux-x64.tar.gz" - sha256 "d966a54a6369ec283203abd257f89e50844ff68551229a463f568dc638dcf4c7" + url "https://github.com/profullstack/tronbrowser.dev/releases/download/v3.15.0/tronbrowser-linux-x64.tar.gz" + sha256 "0870fc5fd4b7acdfa1679f542d038a34e932b65721918cb4c1071e7a6b008779" end def install diff --git a/distribution/scoop/tronbrowser.json b/distribution/scoop/tronbrowser.json index c8a21cce..69d0dd58 100644 --- a/distribution/scoop/tronbrowser.json +++ b/distribution/scoop/tronbrowser.json @@ -1,12 +1,12 @@ { - "version": "0.1.0", + "version": "3.15.0", "description": "Open-source, privacy-first, AI-native browser (Ungoogled Chromium fork).", "homepage": "https://tronbrowser.dev", "license": "MIT", "architecture": { "64bit": { - "url": "https://github.com/profullstack/tronbrowser.dev/releases/download/v0.1.0/tronbrowser-win-x64.zip", - "hash": "TODO-needs-windows-build" + "url": "https://github.com/profullstack/tronbrowser.dev/releases/download/v3.15.0/tronbrowser-win-x64.zip", + "hash": "ebb5b0c7675255accc9975e0ac31a542cb9c9eb1bb700eac18fce8cca681f82c" } }, "bin": [["tronbrowser/tronbrowser.exe", "tron"], ["tronbrowser/tronbrowser.exe", "tronbrowser"]], @@ -14,7 +14,7 @@ "autoupdate": { "architecture": { "64bit": { - "url": "https://github.com/profullstack/tronbrowser.dev/releases/download/v$version/tronbrowser-win-x64.zip" + "url": "https://github.com/profullstack/tronbrowser.dev/releases/download/v3.15.0/tronbrowser-win-x64.zip" } } } diff --git a/distribution/snap/snapcraft.yaml b/distribution/snap/snapcraft.yaml index 21cbf8e2..791a1a76 100644 --- a/distribution/snap/snapcraft.yaml +++ b/distribution/snap/snapcraft.yaml @@ -2,7 +2,7 @@ # and exec the host's Chromium. `snapcraft` builds; publish with `snapcraft upload`. name: tronbrowser base: core24 -version: '0.1.1' +version: '3.15.0' summary: Privacy-first, AI-native browser (Ungoogled Chromium fork) description: | Open-source, privacy-first, AI-native web browser built on Ungoogled Chromium. @@ -20,6 +20,6 @@ apps: parts: tronbrowser: plugin: dump - source: https://github.com/profullstack/tronbrowser.dev/releases/download/v0.1.1/tronbrowser-linux-x64.tar.gz + source: https://github.com/profullstack/tronbrowser.dev/releases/download/v3.15.0/tronbrowser-linux-x64.tar.gz organize: 'tronbrowser/*': './' diff --git a/distribution/winget/Profullstack.TronBrowser.installer.yaml b/distribution/winget/Profullstack.TronBrowser.installer.yaml index a87b59b8..618198a6 100644 --- a/distribution/winget/Profullstack.TronBrowser.installer.yaml +++ b/distribution/winget/Profullstack.TronBrowser.installer.yaml @@ -2,12 +2,12 @@ # manifests/p/Profullstack/TronBrowser//. Needs a Windows installer # (.exe/.msi) or a portable zip artifact — pending the Windows build. PackageIdentifier: Profullstack.TronBrowser -PackageVersion: 0.1.0 +PackageVersion: 3.15.0 InstallerType: zip Installers: - Architecture: x64 - InstallerUrl: https://github.com/profullstack/tronbrowser.dev/releases/download/v0.1.0/tronbrowser-win-x64.zip - InstallerSha256: TODO-NEEDS-WINDOWS-BUILD + InstallerUrl: https://github.com/profullstack/tronbrowser.dev/releases/download/v3.15.0/tronbrowser-win-x64.zip + InstallerSha256: EBB5B0C7675255ACCC9975E0AC31A542CB9C9EB1BB700EAC18FCE8CCA681F82C NestedInstallerType: portable NestedInstallerFiles: - RelativeFilePath: tronbrowser\tronbrowser.exe diff --git a/scripts/open-distribution-pr.sh b/scripts/open-distribution-pr.sh new file mode 100755 index 00000000..3da6cf31 --- /dev/null +++ b/scripts/open-distribution-pr.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# Open a PR with the manifests submit-packages.mjs just refreshed. +# +# Why this exists: the refresh rewrites files under distribution/ on the runner +# and nothing ever persisted them, so every manifest in git stayed frozen at the +# version it was scaffolded with (0.1.0/0.1.1) while releases went out to 3.15.0. +# Those manifests are the input to every channel's submission, so a stale tree +# means even a working submit publishes the wrong version. +# +# A PR rather than a push to main: main is protected, and a bad checksum should +# be reviewable before it reaches a package manager. +set -euo pipefail + +: "${VERSION:?VERSION must be set}" + +if git diff --quiet -- distribution; then + echo "distribution/ already current for v${VERSION}, nothing to commit" + exit 0 +fi + +git config user.name "github-actions[bot]" +git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + +BRANCH="chore/distribution-${VERSION}" + +# A re-run of the same release must not fail on an existing branch. +if git ls-remote --exit-code --heads origin "${BRANCH}" >/dev/null 2>&1; then + echo "branch ${BRANCH} already exists on origin; force-updating it" + git checkout -B "${BRANCH}" + git add distribution + git commit -m "chore(distribution): refresh manifests for v${VERSION}" + git push --force-with-lease origin "${BRANCH}" +else + git checkout -b "${BRANCH}" + git add distribution + git commit -m "chore(distribution): refresh manifests for v${VERSION}" + git push origin "${BRANCH}" +fi + +# `gh pr create` fails if one is already open for the branch, which is fine. +gh pr create \ + --base main \ + --head "${BRANCH}" \ + --title "chore(distribution): refresh manifests for v${VERSION}" \ + --body "Automated manifest refresh from the release pipeline for v${VERSION}. + +Version strings and sha256 checksums are rewritten from the published release +assets by \`scripts/submit-packages.mjs\`." \ + || echo "a PR for ${BRANCH} already exists; branch updated in place" diff --git a/scripts/submit-packages.mjs b/scripts/submit-packages.mjs index db12f592..8f89d05f 100644 --- a/scripts/submit-packages.mjs +++ b/scripts/submit-packages.mjs @@ -10,10 +10,20 @@ // the checked-in manifests under distribution/. Actual submission (push to a tap // repo / scoop bucket / AUR / winget-pkgs PR / choco push) is gated on the // relevant secret being present and is intentionally a no-op without it. -import { readFileSync, writeFileSync, existsSync } from "node:fs"; +// +// 2026-09-24: "submission is gated on the secret" described an intention, not +// code. There was no submit path at all — no push, no PR, no upload — so every +// run only rewrote files under distribution/ and exited. Channels that we own +// outright (a tap, a bucket, AUR, Chocolatey, Snap) now really do publish; the +// ones that are a pull request into somebody else's monorepo (winget, flathub, +// nixpkgs, gentoo, freebsd) still cannot be automated end to end and say so +// rather than reporting success. +import { readFileSync, writeFileSync, existsSync, mkdtempSync } from "node:fs"; import { join, dirname } from "node:path"; import { fileURLToPath } from "node:url"; import { createHash } from "node:crypto"; +import { execFileSync } from "node:child_process"; +import { tmpdir } from "node:os"; const ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); const REPO = process.env.TRONBROWSER_REPO || "profullstack/tronbrowser.dev"; @@ -219,4 +229,238 @@ for (const pm of targets) { } } -console.log(`\nDone (${dryRun ? "dry run" : "manifests updated"}).`); +// --------------------------------------------------------------------------- +// Submission. +// +// Everything above only rewrites files. What follows actually ships them. +// Each channel is gated on its own secret: absent, it prints why it skipped and +// returns cleanly, so a repo with no credentials still gets a green run and a +// refreshed manifest. A channel that has its secret and then fails is a real +// failure and is allowed to break the build — a silent success here is what let +// TronBrowser go three months believing it was published. + +const TAP_REPO = process.env.HOMEBREW_TAP_REPO || "profullstack/homebrew-tap"; +const SCOOP_REPO = process.env.SCOOP_BUCKET_REPO || "profullstack/scoop-bucket"; + +function run(cmd, args, opts = {}) { + return execFileSync(cmd, args, { + encoding: "utf8", + stdio: opts.capture ? "pipe" : "inherit", + cwd: opts.cwd || ROOT, + env: { ...process.env, ...(opts.env || {}) }, + }); +} + +function tmp(prefix) { + return mkdtempSync(join(tmpdir(), `tron-${prefix}-`)); +} + +/** Clone a repo we own, drop one file in, and push it back. */ +function pushFileToRepo({ repo, token, file, dest, message }) { + const dir = tmp(dest.replace(/[^a-z0-9]+/gi, "-")); + const url = `https://x-access-token:${token}@github.com/${repo}.git`; + run("git", ["clone", "--depth", "1", url, dir], { cwd: ROOT }); + run("cp", [join(ROOT, file), join(dir, dest)], { cwd: ROOT }); + run("git", ["config", "user.name", "github-actions[bot]"], { cwd: dir }); + run("git", [ + "config", + "user.email", + "41898282+github-actions[bot]@users.noreply.github.com", + ], { cwd: dir }); + const changed = run("git", ["status", "--porcelain"], { + cwd: dir, + capture: true, + }).trim(); + if (!changed) { + console.log(` ${repo} already current, nothing to push`); + return; + } + run("git", ["add", dest], { cwd: dir }); + run("git", ["commit", "-m", message], { cwd: dir }); + run("git", ["push"], { cwd: dir }); + console.log(` pushed ${dest} to ${repo}`); +} + +/** Channels that are a PR into a third party's monorepo. */ +function upstreamPr(pm, repo, doc) { + console.log( + ` ${pm}: needs a pull request into ${repo}, which is a human review queue.`, + ); + console.log(` manifest refreshed; open the PR by hand: ${doc}`); +} + +const SUBMITTERS = { + homebrew: () => { + const token = process.env.HOMEBREW_TAP_TOKEN; + if (!token) return skip("homebrew", "HOMEBREW_TAP_TOKEN"); + pushFileToRepo({ + repo: TAP_REPO, + token, + file: "distribution/homebrew/tronbrowser.rb", + dest: "Formula/tronbrowser.rb", + message: `tronbrowser ${version}`, + }); + }, + + scoop: () => { + const token = process.env.SCOOP_BUCKET_TOKEN; + if (!token) return skip("scoop", "SCOOP_BUCKET_TOKEN"); + pushFileToRepo({ + repo: SCOOP_REPO, + token, + file: "distribution/scoop/tronbrowser.json", + dest: "bucket/tronbrowser.json", + message: `tronbrowser ${version}`, + }); + }, + + aur: () => { + const key = process.env.AUR_SSH_KEY; + if (!key) return skip("aur", "AUR_SSH_KEY"); + const dir = tmp("aur"); + const keyfile = join(dir, "aur_key"); + writeFileSync(keyfile, key.endsWith("\n") ? key : `${key}\n`, { + mode: 0o600, + }); + // AUR only speaks ssh, and the runner has never seen the host before. + const ssh = `ssh -i ${keyfile} -o StrictHostKeyChecking=accept-new`; + const repoDir = join(dir, "tronbrowser-bin"); + run("git", ["clone", "ssh://aur@aur.archlinux.org/tronbrowser-bin.git", repoDir], { + cwd: ROOT, + env: { GIT_SSH_COMMAND: ssh }, + }); + run("cp", [join(ROOT, "distribution/aur/PKGBUILD"), join(repoDir, "PKGBUILD")]); + // .SRCINFO is generated, and the AUR rejects a push whose .SRCINFO disagrees + // with the PKGBUILD. makepkg is not on a GitHub runner, so write it from the + // PKGBUILD we already have rather than shelling out to a tool that is absent. + writeSrcinfo(repoDir); + run("git", ["config", "user.name", "TronBrowser CI"], { cwd: repoDir }); + run("git", ["config", "user.email", "bot@tronbrowser.dev"], { cwd: repoDir }); + const changed = run("git", ["status", "--porcelain"], { + cwd: repoDir, + capture: true, + }).trim(); + if (!changed) return console.log(" AUR already current, nothing to push"); + run("git", ["add", "PKGBUILD", ".SRCINFO"], { cwd: repoDir }); + run("git", ["commit", "-m", `tronbrowser-bin ${version}`], { cwd: repoDir }); + run("git", ["push"], { cwd: repoDir, env: { GIT_SSH_COMMAND: ssh } }); + console.log(" pushed PKGBUILD to the AUR"); + }, + + chocolatey: () => { + const key = process.env.CHOCOLATEY_API_KEY; + if (!key) return skip("chocolatey", "CHOCOLATEY_API_KEY"); + const dir = join(ROOT, "distribution/chocolatey"); + run("choco", ["pack", "tronbrowser.nuspec", "--outputdirectory", dir], { + cwd: dir, + }); + run("choco", [ + "push", + join(dir, `tronbrowser.${version}.nupkg`), + "--source", + "https://push.chocolatey.org/", + "--api-key", + key, + ], { cwd: dir }); + console.log(" pushed to Chocolatey"); + }, + + snap: () => { + const creds = process.env.SNAPCRAFT_STORE_CREDENTIALS; + if (!creds) return skip("snap", "SNAPCRAFT_STORE_CREDENTIALS"); + // snapcraft reads the credentials straight out of the environment; building + // the snap itself needs LXD and happens in the release job, not here. + const snap = process.env.SNAP_FILE; + if (!snap || !existsSync(snap)) { + console.log( + " snap: SNAPCRAFT_STORE_CREDENTIALS is set but no built .snap was passed", + ); + console.log(" set SNAP_FILE to the artifact built by the release job"); + return; + } + run("snapcraft", ["upload", "--release", "stable", snap]); + console.log(" uploaded to the Snap Store"); + }, + + winget: () => + upstreamPr( + "winget", + "microsoft/winget-pkgs", + "https://github.com/microsoft/winget-pkgs/blob/master/CONTRIBUTING.md", + ), + flatpak: () => + upstreamPr( + "flatpak", + "flathub/flathub", + "https://docs.flathub.org/docs/for-app-authors/submission", + ), + nix: () => + upstreamPr( + "nix", + "NixOS/nixpkgs", + "https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md", + ), + gentoo: () => + upstreamPr( + "gentoo", + "an ebuild overlay", + "https://wiki.gentoo.org/wiki/Ebuild_repository", + ), + freebsd: () => + upstreamPr( + "freebsd", + "freebsd/freebsd-ports", + "https://docs.freebsd.org/en/books/porters-handbook/", + ), + + // Built and attached to the GitHub release itself; there is no downstream. + apt: () => console.log(" apt: attached to the GitHub release, nothing to submit"), + rpm: () => console.log(" rpm: attached to the GitHub release, nothing to submit"), + appimage: () => + console.log(" appimage: attached to the GitHub release, nothing to submit"), +}; + +function skip(pm, secret) { + console.log(` ${pm}: ${secret} not set, manifest refreshed but not submitted`); +} + +/** + * Write .SRCINFO from the PKGBUILD. + * + * Only the handful of fields our PKGBUILD actually sets — enough for the AUR to + * accept the push and for a helper to resolve the package. If PKGBUILD grows + * fields beyond these, this needs to grow with it. + */ +function writeSrcinfo(repoDir) { + const pkgbuild = readFileSync(join(repoDir, "PKGBUILD"), "utf8"); + const field = (name) => { + const m = pkgbuild.match(new RegExp(`^${name}=(.+)$`, "m")); + return m ? m[1].replace(/^['"(]+|['")]+$/g, "") : ""; + }; + const lines = [ + `pkgbase = ${field("pkgname")}`, + `\tpkgdesc = ${field("pkgdesc")}`, + `\tpkgver = ${field("pkgver")}`, + `\tpkgrel = ${field("pkgrel")}`, + `\turl = ${field("url")}`, + `\tarch = ${field("arch")}`, + `\tlicense = ${field("license")}`, + `\tsource = ${field("source")}`, + `\tsha256sums = ${field("sha256sums")}`, + "", + `pkgname = ${field("pkgname")}`, + "", + ]; + writeFileSync(join(repoDir, ".SRCINFO"), lines.join("\n")); +} + +if (!dryRun) { + for (const pm of targets) { + const submit = SUBMITTERS[pm]; + if (!submit) continue; + console.log(`\n== submit ${pm} ==`); + submit(); + } +} + +console.log(`\nDone (${dryRun ? "dry run" : "manifests updated and submitted"}).`);