Preserve both pre-cutoff dependency branch histories #10
No files matched your search
@@ -26,7 +26,12 @@ See [`docs/release-runbook.md`](../release-runbook.md). In short: `node scripts/
|
||||
release with `dist/qqq-*` and `dist/SHA256SUMS`, `node scripts/update-packaging.mjs <that SHA256SUMS>`,
|
||||
copy `homebrew-tap/Formula/qqq.rb` to the tap and `qqq.json` to the bucket (the bucket's Excavator
|
||||
also picks up new releases by itself). Use the uploaded sums, not a
|
||||
local rebuild: each build stamps its commit, so checksums differ between builds.
|
||||
local rebuild: each build stamps its commit, so checksums differ between builds. The script exits 1 and writes
|
||||
nothing when a sum is missing or malformed, and never writes zeros; check the result anyway with
|
||||
`git diff` and `grep -c 0000000000000000 docs/packaging/qqq.json docs/packaging/homebrew-tap/Formula/qqq.rb`
|
||||
(both must print 0) before copying the files out. The tap's CI and the bucket's manifest tests would catch
|
||||
zeros (a download that does not match) only if their pull requests are opened and their checks are read;
|
||||
checkpoint the sums here first, not there.
|
||||
|
||||
## Where the formula and manifest live
|
||||
|
||||
|
||||
@@ -12,22 +12,22 @@ class Qqq < Formula
|
||||
on_macos do
|
||||
on_arm do
|
||||
url "https://github.com/QRun-IO/qqq-cli/releases/download/cli-v#{version}/qqq-darwin-arm64"
|
||||
sha256 "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
sha256 "5017a32ac5031d9146d541381099a959e5c19bbf04c48f725045d89d6007b211"
|
||||
end
|
||||
on_intel do
|
||||
url "https://github.com/QRun-IO/qqq-cli/releases/download/cli-v#{version}/qqq-darwin-x64"
|
||||
sha256 "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
sha256 "eb9b1d43d24b639118d94b175c343080a39ae9ba64c24645c1792ff3b16a37f1"
|
||||
end
|
||||
end
|
||||
|
||||
on_linux do
|
||||
on_arm do
|
||||
url "https://github.com/QRun-IO/qqq-cli/releases/download/cli-v#{version}/qqq-linux-arm64"
|
||||
sha256 "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
sha256 "25f513bdda13bbe40cf536844eebc1e3a7e21cf7804024f25ebe7c42793d7ebc"
|
||||
end
|
||||
on_intel do
|
||||
url "https://github.com/QRun-IO/qqq-cli/releases/download/cli-v#{version}/qqq-linux-x64"
|
||||
sha256 "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
sha256 "804d06cb7c0012c2f185ae5d94c6bb8f9e2482a440bb3c165361f1a14c941e41"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ here (`Formula/qctl.rb`) once this tap exists, with `homebrew-qctl` kept as a po
|
||||
The formula is generated in qqq-cli: after a `cli-v<version>` GitHub release, run
|
||||
`node scripts/update-packaging.mjs <release SHA256SUMS>` there and copy
|
||||
`docs/packaging/homebrew-tap/Formula/qqq.rb` here. CI (qqq-orb `homebrew-tap` profile) fetches every
|
||||
platform's download, installs the formula and runs its test.
|
||||
platform's download, installs the formula and runs its test, which fails on a wrong or all-zero sum, but
|
||||
only once the pull request here is opened and its checks are read. The script refuses to write missing or
|
||||
malformed sums; still compare the sums in the diff with the release's `SHA256SUMS` before opening the PR.
|
||||
|
||||
Apache-2.0
|
||||
@@ -10,7 +10,7 @@
|
||||
"architecture": {
|
||||
"64bit": {
|
||||
"url": "https://github.com/QRun-IO/qqq-cli/releases/download/cli-v1.0.0/qqq-windows-x64.exe",
|
||||
"hash": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
"hash": "cf418d7842a227cee412171878228004f9bc5098a272c64b89512d1e2d06a176"
|
||||
}
|
||||
},
|
||||
"bin": [
|
||||
|
||||
@@ -180,9 +180,15 @@ release (the channel Homebrew and Scoop follow); a release candidate is reached
|
||||
```sh
|
||||
gh release download cli-v1.0.0 --repo QRun-IO/qqq-cli -p SHA256SUMS -D /tmp/qqq-1.0.0
|
||||
node scripts/update-packaging.mjs /tmp/qqq-1.0.0/SHA256SUMS
|
||||
git diff docs/packaging # every sha256 differs from the placeholder, none is all zeros
|
||||
git commit -S -am "packaging: qqq 1.0.0" && git push # in qqq-cli, through a pull request
|
||||
```
|
||||
|
||||
The script exits 1 and writes nothing if `SHA256SUMS` lacks a target or has a malformed sum. Compare each sum
|
||||
in the diff with the release's `SHA256SUMS` by eye before committing: the tap's CI and the bucket's manifest
|
||||
tests catch a wrong sum (the download will not match) only when someone opens those pull requests and reads
|
||||
their checks.
|
||||
|
||||
Then copy `docs/packaging/homebrew-tap/Formula/qqq.rb` to `Formula/qqq.rb` in `QRun-IO/homebrew-tap`
|
||||
and `docs/packaging/qqq.json` to `bucket/qqq.json` in `QRun-IO/scoop-bucket`, a pull request on each. The tap's
|
||||
CI fetches every platform's download, installs the formula and runs its test (which insists on
|
||||
|
||||
Generated
+368
-7
@@ -15,7 +15,7 @@
|
||||
"devDependencies": {
|
||||
"@stoplight/prism-cli": "5.16.0",
|
||||
"@types/node": "22.15.3",
|
||||
"typescript": "5.8.3",
|
||||
"typescript": "7.0.2",
|
||||
"yaml": "2.9.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -590,6 +590,346 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-aix-ppc64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz",
|
||||
"integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-darwin-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-darwin-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-freebsd-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-freebsd-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-arm": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz",
|
||||
"integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-loong64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz",
|
||||
"integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-mips64el": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz",
|
||||
"integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-ppc64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz",
|
||||
"integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-riscv64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz",
|
||||
"integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-s390x": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz",
|
||||
"integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-netbsd-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-netbsd-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-openbsd-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-openbsd-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-sunos-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-win32-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-win32-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/abstract-logging": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz",
|
||||
@@ -2708,17 +3048,38 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.8.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz",
|
||||
"integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
"tsc": "bin/tsc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
"node": ">=16.20.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@typescript/typescript-aix-ppc64": "7.0.2",
|
||||
"@typescript/typescript-darwin-arm64": "7.0.2",
|
||||
"@typescript/typescript-darwin-x64": "7.0.2",
|
||||
"@typescript/typescript-freebsd-arm64": "7.0.2",
|
||||
"@typescript/typescript-freebsd-x64": "7.0.2",
|
||||
"@typescript/typescript-linux-arm": "7.0.2",
|
||||
"@typescript/typescript-linux-arm64": "7.0.2",
|
||||
"@typescript/typescript-linux-loong64": "7.0.2",
|
||||
"@typescript/typescript-linux-mips64el": "7.0.2",
|
||||
"@typescript/typescript-linux-ppc64": "7.0.2",
|
||||
"@typescript/typescript-linux-riscv64": "7.0.2",
|
||||
"@typescript/typescript-linux-s390x": "7.0.2",
|
||||
"@typescript/typescript-linux-x64": "7.0.2",
|
||||
"@typescript/typescript-netbsd-arm64": "7.0.2",
|
||||
"@typescript/typescript-netbsd-x64": "7.0.2",
|
||||
"@typescript/typescript-openbsd-arm64": "7.0.2",
|
||||
"@typescript/typescript-openbsd-x64": "7.0.2",
|
||||
"@typescript/typescript-sunos-x64": "7.0.2",
|
||||
"@typescript/typescript-win32-arm64": "7.0.2",
|
||||
"@typescript/typescript-win32-x64": "7.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
|
||||
+3
-2
@@ -18,7 +18,8 @@
|
||||
"spec:merge-extensions": "node scripts/merge-extensions.mjs",
|
||||
"generate": "npm run generate -w @qrun-io/qqq-ui-api-client && node scripts/gen-operations.mjs",
|
||||
"build": "npm run build -w @qrun-io/qqq-ui-api-client && npm run build -w @qrun-io/qqq-core && npm run build -w @qrun-io/qqq-ui-api-conformance && npm run build -w @qrun-io/qqq-cli",
|
||||
"test": "npm test --workspaces --if-present",
|
||||
"test": "npm test --workspaces --if-present && npm run test:scripts",
|
||||
"test:scripts": "node --test scripts/update-packaging.test.mjs",
|
||||
"mock": "prism mock --dynamic --port 4010 packages/ui-api-client/openapi/qqq-v1.json",
|
||||
"prepublishOnly": "npm run build",
|
||||
"lint": "node scripts/lint.mjs",
|
||||
@@ -30,7 +31,7 @@
|
||||
"devDependencies": {
|
||||
"@stoplight/prism-cli": "5.16.0",
|
||||
"@types/node": "22.15.3",
|
||||
"typescript": "5.8.3",
|
||||
"typescript": "7.0.2",
|
||||
"yaml": "2.9.1"
|
||||
}
|
||||
}
|
||||
@@ -10,36 +10,79 @@
|
||||
* Run it on the binaries that were uploaded to the GitHub release, not on a local rebuild: the
|
||||
* commit is stamped into each binary, so every build has different checksums.
|
||||
*
|
||||
* Refuses to write anything (exit 1, both files untouched) when a sum is missing, is not 64 lowercase hex digits,
|
||||
* is all zeros, or when a placeholder in the files is left unfilled.
|
||||
*
|
||||
* Usage: node scripts/update-packaging.mjs [dist/SHA256SUMS]
|
||||
*/
|
||||
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { readFileSync, realpathSync, writeFileSync } from 'node:fs'
|
||||
import { join, resolve } from 'node:path'
|
||||
|
||||
const HEX64 = /^[0-9a-f]{64}$/
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
const sumsPath = resolve(process.argv[2] ?? join(root, 'dist/SHA256SUMS'))
|
||||
const version = JSON.parse(readFileSync(join(root, 'packages/cli/package.json'), 'utf8')).version
|
||||
const sums = new Map(readFileSync(sumsPath, 'utf8').trim().split('\n').map((line) => line.split(/\s+/).reverse()))
|
||||
const FORMULA_SUMS = /(url "[^"]*\/(qqq-[a-z0-9-]+)"\n\s*sha256 ")([0-9a-f]{64})"/g
|
||||
|
||||
function sum(file) {
|
||||
const hash = sums.get(file)
|
||||
if (!hash) {
|
||||
console.error(`update-packaging: ${sumsPath} has no ${file}`)
|
||||
process.exit(1)
|
||||
/** Parses `shasum -a 256` output (`<hash> <file>`, `*` before the name tolerated) into a Map of file to hash. */
|
||||
export function parseSums(text) {
|
||||
const sums = new Map()
|
||||
for (const line of text.split('\n')) {
|
||||
if (line.trim() === '') continue
|
||||
const match = line.match(/^(\S+)\s+\*?(\S+)$/)
|
||||
if (!match) throw new Error(`unparseable SHA256SUMS line: ${JSON.stringify(line)}`)
|
||||
sums.set(match[2], match[1].toLowerCase())
|
||||
}
|
||||
return sums
|
||||
}
|
||||
|
||||
function sumFor(sums, file) {
|
||||
const hash = sums.get(file)
|
||||
if (hash === undefined) throw new Error(`SHA256SUMS has no ${file}`)
|
||||
if (!HEX64.test(hash)) throw new Error(`SHA256SUMS has a malformed sum for ${file}: ${JSON.stringify(hash)}`)
|
||||
if (/^0+$/.test(hash)) throw new Error(`SHA256SUMS has an all-zero sum for ${file}`)
|
||||
return hash
|
||||
}
|
||||
|
||||
const formulaPath = join(root, 'docs/packaging/homebrew-tap/Formula/qqq.rb')
|
||||
let formula = readFileSync(formulaPath, 'utf8').replace(/^(\s*version ")[^"]+"/m, `$1${version}"`)
|
||||
formula = formula.replace(/(url "[^"]*\/(qqq-[a-z0-9-]+)"\n\s*sha256 ")[0-9a-f]{64}"/g, (_, head, file) => `${head}${sum(file)}"`)
|
||||
writeFileSync(formulaPath, formula)
|
||||
/** Returns the new text of both packaging files; throws, leaving the caller nothing to write, on any problem. */
|
||||
export function updatePackaging({ version, sums, formula, manifest }) {
|
||||
let formulaCount = 0
|
||||
const newFormula = formula
|
||||
.replace(/^(\s*version ")[^"]+"/m, `$1${version}"`)
|
||||
.replace(FORMULA_SUMS, (_, head, file) => {
|
||||
formulaCount++
|
||||
return `${head}${sumFor(sums, file)}"`
|
||||
})
|
||||
if (formulaCount === 0) throw new Error('the formula has no url/sha256 pairs to fill')
|
||||
const left = newFormula.match(/sha256 "(?![0-9a-f]{64}")[^"]*"/g)
|
||||
if (left || /sha256 "0{64}"/.test(newFormula)) throw new Error(`the formula still has unfilled sha256 values: ${left ?? 'zeros'}`)
|
||||
|
||||
const manifestPath = join(root, 'docs/packaging/qqq.json')
|
||||
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
|
||||
manifest.version = version
|
||||
manifest.architecture['64bit'].url = `https://github.com/QRun-IO/qqq-cli/releases/download/cli-v${version}/qqq-windows-x64.exe`
|
||||
manifest.architecture['64bit'].hash = sum('qqq-windows-x64.exe')
|
||||
writeFileSync(manifestPath, JSON.stringify(manifest, null, 4) + '\n')
|
||||
const parsed = JSON.parse(manifest)
|
||||
parsed.version = version
|
||||
parsed.architecture['64bit'].url = `https://github.com/QRun-IO/qqq-cli/releases/download/cli-v${version}/qqq-windows-x64.exe`
|
||||
parsed.architecture['64bit'].hash = sumFor(sums, 'qqq-windows-x64.exe')
|
||||
return { formula: newFormula, manifest: JSON.stringify(parsed, null, 4) + '\n', formulaCount }
|
||||
}
|
||||
|
||||
console.log(`docs/packaging/homebrew-tap/Formula/qqq.rb and docs/packaging/qqq.json now name ${version} with the sums from ${sumsPath}`)
|
||||
function main() {
|
||||
const sumsPath = resolve(process.argv[2] ?? join(root, 'dist/SHA256SUMS'))
|
||||
const version = JSON.parse(readFileSync(join(root, 'packages/cli/package.json'), 'utf8')).version
|
||||
const formulaPath = join(root, 'docs/packaging/homebrew-tap/Formula/qqq.rb')
|
||||
const manifestPath = join(root, 'docs/packaging/qqq.json')
|
||||
try {
|
||||
const out = updatePackaging({
|
||||
version,
|
||||
sums: parseSums(readFileSync(sumsPath, 'utf8')),
|
||||
formula: readFileSync(formulaPath, 'utf8'),
|
||||
manifest: readFileSync(manifestPath, 'utf8'),
|
||||
})
|
||||
writeFileSync(formulaPath, out.formula)
|
||||
writeFileSync(manifestPath, out.manifest)
|
||||
console.log(`docs/packaging/homebrew-tap/Formula/qqq.rb (${out.formulaCount} sums) and docs/packaging/qqq.json now name ${version} with the sums from ${sumsPath}`)
|
||||
} catch (error) {
|
||||
console.error(`update-packaging: ${error.message}; nothing was written`)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Run only as a script, not when the tests import it (realpath: argv[1] may go through a symlink such as macOS /var).
|
||||
if (process.argv[1] && realpathSync(process.argv[1]) === realpathSync(import.meta.filename)) main()
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2026 QRun.IO, Inc.
|
||||
* Licensed under the Apache License, Version 2.0 (see LICENSE).
|
||||
*/
|
||||
|
||||
/** Tests for scripts/update-packaging.mjs. Run: node --test scripts/update-packaging.test.mjs */
|
||||
|
||||
import assert from 'node:assert/strict'
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { cpSync, mkdtempSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { test } from 'node:test'
|
||||
import { parseSums, updatePackaging } from './update-packaging.mjs'
|
||||
|
||||
const ZERO = '0'.repeat(64)
|
||||
const h = (c) => c.repeat(64)
|
||||
const FILES = ['qqq-darwin-arm64', 'qqq-darwin-x64', 'qqq-linux-arm64', 'qqq-linux-x64']
|
||||
const sumsText = (omit = []) =>
|
||||
[...FILES, 'qqq-linux-x64-musl', 'qqq-windows-x64.exe'].filter((f) => !omit.includes(f)).map((f, i) => `${'abcdef0123456'[i].repeat(64)} ${f}`).join('\n') + '\n'
|
||||
const formula = `class Qqq < Formula
|
||||
version "0.0.0"
|
||||
${FILES.map((f) => ` url "https://github.com/QRun-IO/qqq-cli/releases/download/cli-v#{version}/${f}"\n sha256 "${ZERO}"`).join('\n')}
|
||||
end
|
||||
`
|
||||
const manifest = JSON.stringify({ version: '0.0.0', architecture: { '64bit': { url: 'x', hash: ZERO } } }, null, 4) + '\n'
|
||||
|
||||
test('fills every sum from shasum output and never leaves zeros', () => {
|
||||
const out = updatePackaging({ version: '1.0.0', sums: parseSums(sumsText()), formula, manifest })
|
||||
assert.equal(out.formulaCount, 4)
|
||||
assert.ok(!out.formula.includes(ZERO) && !out.manifest.includes(ZERO))
|
||||
assert.match(out.formula, /version "1\.0\.0"/)
|
||||
assert.ok(out.formula.includes(`qqq-darwin-arm64"\n sha256 "${h('a')}"`))
|
||||
assert.equal(JSON.parse(out.manifest).architecture['64bit'].hash, h('f'))
|
||||
})
|
||||
|
||||
test('a missing target throws', () => {
|
||||
assert.throws(() => updatePackaging({ version: '1.0.0', sums: parseSums(sumsText(['qqq-linux-x64'])), formula, manifest }), /no qqq-linux-x64/)
|
||||
assert.throws(() => updatePackaging({ version: '1.0.0', sums: parseSums(sumsText(['qqq-windows-x64.exe'])), formula, manifest }), /no qqq-windows-x64\.exe/)
|
||||
})
|
||||
|
||||
test('malformed, short, uppercase-free or zero sums throw', () => {
|
||||
for (const bad of ['abc', ZERO, 'g'.repeat(64)]) {
|
||||
const sums = parseSums(sumsText().replace(h('a'), bad))
|
||||
assert.throws(() => updatePackaging({ version: '1.0.0', sums, formula, manifest }), /malformed|all-zero/)
|
||||
}
|
||||
assert.throws(() => parseSums('only-one-column\n'), /unparseable/)
|
||||
})
|
||||
|
||||
test('a formula with nothing to fill throws', () => {
|
||||
assert.throws(() => updatePackaging({ version: '1.0.0', sums: parseSums(sumsText()), formula: 'class Qqq < Formula\nend\n', manifest }), /no url\/sha256/)
|
||||
})
|
||||
|
||||
test('the CLI exits 1 and writes nothing when a sum is missing', () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), 'update-packaging-'))
|
||||
mkdirSync(join(dir, 'scripts'))
|
||||
cpSync(join(import.meta.dirname, 'update-packaging.mjs'), join(dir, 'scripts/update-packaging.mjs'))
|
||||
mkdirSync(join(dir, 'packages/cli'), { recursive: true })
|
||||
writeFileSync(join(dir, 'packages/cli/package.json'), '{"version":"1.0.0"}')
|
||||
mkdirSync(join(dir, 'docs/packaging/homebrew-tap/Formula'), { recursive: true })
|
||||
writeFileSync(join(dir, 'docs/packaging/homebrew-tap/Formula/qqq.rb'), formula)
|
||||
writeFileSync(join(dir, 'docs/packaging/qqq.json'), manifest)
|
||||
writeFileSync(join(dir, 'SHA256SUMS'), sumsText(['qqq-linux-arm64']))
|
||||
const run = spawnSync(process.execPath, [join(dir, 'scripts/update-packaging.mjs'), join(dir, 'SHA256SUMS')], { encoding: 'utf8' })
|
||||
assert.equal(run.status, 1)
|
||||
assert.match(run.stderr, /nothing was written/)
|
||||
assert.equal(readFileSync(join(dir, 'docs/packaging/homebrew-tap/Formula/qqq.rb'), 'utf8'), formula)
|
||||
assert.equal(readFileSync(join(dir, 'docs/packaging/qqq.json'), 'utf8'), manifest)
|
||||
writeFileSync(join(dir, 'SHA256SUMS'), sumsText())
|
||||
const ok = spawnSync(process.execPath, [join(dir, 'scripts/update-packaging.mjs'), join(dir, 'SHA256SUMS')], { encoding: 'utf8' })
|
||||
assert.equal(ok.status, 0, ok.stderr)
|
||||
assert.ok(!readFileSync(join(dir, 'docs/packaging/qqq.json'), 'utf8').includes(ZERO))
|
||||
})
|
||||
Reference in new issue
Block a user