3 Commits

Author SHA1 Message Date
4588bdf40c Make macOS release upload idempotent across re-runs
All checks were successful
Build App / compute-version (push) Successful in 2s
Build App / build-macos (push) Successful in 2m25s
Build App / build-windows (push) Successful in 4m42s
Build App / build-linux (push) Successful in 8m54s
Build App / create-tag (push) Successful in 3s
Build App / sync-to-github (push) Successful in 10s
Previous fix only addressed the network flake; a re-run after any
upload failure still tripped over the leftover release record. The
naive POST /releases got 409 from Gitea, the grep-pipe parser yielded
an empty RELEASE_ID, and pipefail aborted with an opaque exit 1.

Now:
- Look up the release by tag first; reuse on 200, create on 404, fail
  loudly on anything else.
- Validate RELEASE_ID is non-empty and surface the response body if
  parsing fails.
- Before uploading each asset, check whether the release already has
  an asset with that name (from a partial prior run) and DELETE it so
  the POST is replace-not-conflict.
- Set -euo pipefail explicitly so the script's failure modes are
  predictable rather than dependent on the runner's default flags.

Network hardening from the previous commit (HTTP/1.1, retries, -f) is
preserved. Linux and Windows blocks unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 18:13:25 -07:00
b607cf3681 Harden macOS release upload against curl exit 92
Some checks failed
Build App / compute-version (push) Successful in 3s
Build App / build-windows (push) Successful in 4m5s
Build App / build-linux (push) Successful in 9m53s
Build App / build-macos (push) Failing after 2m30s
Build App / create-tag (push) Has been skipped
Build App / sync-to-github (push) Has been skipped
macOS upload has been intermittently failing with curl exit 92
("HTTP/2 stream not closed cleanly") for several releases (v0.3.12,
v0.3.10, v0.3.1 all landed with empty asset arrays despite the per-tag
release record being created). It is not a size issue — Linux uploads
the 81MB AppImage on the same Gitea instance without trouble while the
Mac dmg is only 13.6MB.

Adds `--http1.1` to sidestep HTTP/2 stream multiplexing flakes on the
macOS runner, `-f` so HTTP errors no longer fail silently under `-s`,
and `--retry 5 --retry-all-errors --retry-delay 5 --max-time 600` to
absorb transient drops. Linux and Windows blocks unchanged; an inline
note in the YAML calls out where to mirror this if those start
failing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 17:28:08 -07:00
21a85dc977 Bump @tauri-apps/api and @tauri-apps/cli to 2.11.0 in package-lock
Some checks failed
Build App / compute-version (push) Successful in 3s
Build App / build-macos (push) Failing after 3m24s
Build App / build-windows (push) Successful in 4m9s
Build App / build-linux (push) Successful in 7m20s
Build App / create-tag (push) Has been skipped
Build App / sync-to-github (push) Has been skipped
Mac/Windows release builds failed the Tauri version-mismatch check:
tauri (2.11.0) vs @tauri-apps/api (2.10.1). The Linux fix only updated
the Rust lockfile; the npm lockfile was still at 2.10.x. Both lockfiles
now resolve to 2.11.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 17:09:22 -07:00
2 changed files with 111 additions and 60 deletions

View File

@@ -264,21 +264,72 @@ jobs:
env: env:
TOKEN: ${{ secrets.REGISTRY_TOKEN }} TOKEN: ${{ secrets.REGISTRY_TOKEN }}
run: | run: |
set -euo pipefail
TAG="v${{ needs.compute-version.outputs.version }}-mac" TAG="v${{ needs.compute-version.outputs.version }}-mac"
# Create release
curl -s -X POST \ # Idempotent get-or-create. macOS upload has historically failed
# mid-stream (curl exit 92, exit 28), leaving the release record
# with empty assets. A naive POST /releases on the next run hits
# 409 from Gitea for the duplicate tag, the JSON parse below
# then yields an empty RELEASE_ID, and pipefail aborts with an
# opaque exit 1. Look the release up by tag first; create only
# if it doesn't exist; reuse the existing id otherwise.
HTTP_CODE=$(curl -sS -o release.json -w '%{http_code}' \
-H "Authorization: token ${TOKEN}" \ -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \ "${GITEA_URL}/api/v1/repos/${REPO}/releases/tags/${TAG}")
-d "{\"tag_name\": \"${TAG}\", \"name\": \"Triple-C v${{ needs.compute-version.outputs.version }} (macOS)\", \"body\": \"Automated build from commit ${{ gitea.sha }}\"}" \ case "${HTTP_CODE}" in
"${GITEA_URL}/api/v1/repos/${REPO}/releases" > release.json 200)
RELEASE_ID=$(cat release.json | grep -o '"id":[0-9]*' | head -1 | grep -o '[0-9]*') echo "Release ${TAG} already exists, reusing"
;;
404)
echo "Release ${TAG} not found, creating"
curl -fsS -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"tag_name\": \"${TAG}\", \"name\": \"Triple-C v${{ needs.compute-version.outputs.version }} (macOS)\", \"body\": \"Automated build from commit ${{ gitea.sha }}\"}" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases" > release.json
;;
*)
echo "Unexpected HTTP ${HTTP_CODE} from get-release-by-tag" >&2
cat release.json >&2 || true
exit 1
;;
esac
RELEASE_ID=$(grep -o '"id":[0-9]*' release.json | head -1 | grep -o '[0-9]*' || true)
if [ -z "${RELEASE_ID}" ]; then
echo "Failed to parse release id; response was:" >&2
cat release.json >&2
exit 1
fi
echo "Release ID: ${RELEASE_ID}" echo "Release ID: ${RELEASE_ID}"
# Upload each artifact
# Upload each artifact. If an asset with the same name already
# exists on the release (left over from a partial prior run),
# delete it first so the upload is replace-not-conflict.
# Network hardening: HTTP/1.1 to dodge HTTP/2 stream flakes
# the macOS runner has hit, retries with backoff for transient
# drops, and -f so HTTP errors stop being silently swallowed.
for file in artifacts/*; do for file in artifacts/*; do
[ -f "$file" ] || continue [ -f "$file" ] || continue
filename=$(basename "$file") filename=$(basename "$file")
EXISTING_ID=$(curl -sS \
-H "Authorization: token ${TOKEN}" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets" \
| python3 -c "import json,sys; t=sys.argv[1]; print(next((a['id'] for a in json.load(sys.stdin) if a.get('name')==t), ''))" "${filename}" || true)
if [ -n "${EXISTING_ID}" ]; then
echo "Deleting existing asset ${filename} (id ${EXISTING_ID})"
curl -fsS -X DELETE \
-H "Authorization: token ${TOKEN}" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets/${EXISTING_ID}"
fi
echo "Uploading ${filename}..." echo "Uploading ${filename}..."
curl -s -X POST \ curl -fsS --http1.1 \
--retry 5 --retry-all-errors --retry-delay 5 \
--max-time 600 \
-X POST \
-H "Authorization: token ${TOKEN}" \ -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/octet-stream" \ -H "Content-Type: application/octet-stream" \
--data-binary "@${file}" \ --data-binary "@${file}" \

104
app/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "triple-c", "name": "triple-c",
"version": "0.2.0", "version": "0.3.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "triple-c", "name": "triple-c",
"version": "0.2.0", "version": "0.3.0",
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2", "@tauri-apps/api": "^2",
"@tauri-apps/plugin-dialog": "^2.7.0", "@tauri-apps/plugin-dialog": "^2.7.0",
@@ -1757,9 +1757,9 @@
} }
}, },
"node_modules/@tauri-apps/api": { "node_modules/@tauri-apps/api": {
"version": "2.10.1", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.10.1.tgz", "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.0.tgz",
"integrity": "sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==", "integrity": "sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA==",
"license": "Apache-2.0 OR MIT", "license": "Apache-2.0 OR MIT",
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@@ -1767,9 +1767,9 @@
} }
}, },
"node_modules/@tauri-apps/cli": { "node_modules/@tauri-apps/cli": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.10.0.tgz", "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.0.tgz",
"integrity": "sha512-ZwT0T+7bw4+DPCSWzmviwq5XbXlM0cNoleDKOYPFYqcZqeKY31KlpoMW/MOON/tOFBPgi31a2v3w9gliqwL2+Q==", "integrity": "sha512-W5Wbuqsb2pHFPTj4TaRNKTj5rwXhDShPiLSY9T18y4ouSR/NNCptAEFxFsBtyNRgL6Vs1a/q9LzfqqYzEwC+Jw==",
"dev": true, "dev": true,
"license": "Apache-2.0 OR MIT", "license": "Apache-2.0 OR MIT",
"bin": { "bin": {
@@ -1783,23 +1783,23 @@
"url": "https://opencollective.com/tauri" "url": "https://opencollective.com/tauri"
}, },
"optionalDependencies": { "optionalDependencies": {
"@tauri-apps/cli-darwin-arm64": "2.10.0", "@tauri-apps/cli-darwin-arm64": "2.11.0",
"@tauri-apps/cli-darwin-x64": "2.10.0", "@tauri-apps/cli-darwin-x64": "2.11.0",
"@tauri-apps/cli-linux-arm-gnueabihf": "2.10.0", "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.0",
"@tauri-apps/cli-linux-arm64-gnu": "2.10.0", "@tauri-apps/cli-linux-arm64-gnu": "2.11.0",
"@tauri-apps/cli-linux-arm64-musl": "2.10.0", "@tauri-apps/cli-linux-arm64-musl": "2.11.0",
"@tauri-apps/cli-linux-riscv64-gnu": "2.10.0", "@tauri-apps/cli-linux-riscv64-gnu": "2.11.0",
"@tauri-apps/cli-linux-x64-gnu": "2.10.0", "@tauri-apps/cli-linux-x64-gnu": "2.11.0",
"@tauri-apps/cli-linux-x64-musl": "2.10.0", "@tauri-apps/cli-linux-x64-musl": "2.11.0",
"@tauri-apps/cli-win32-arm64-msvc": "2.10.0", "@tauri-apps/cli-win32-arm64-msvc": "2.11.0",
"@tauri-apps/cli-win32-ia32-msvc": "2.10.0", "@tauri-apps/cli-win32-ia32-msvc": "2.11.0",
"@tauri-apps/cli-win32-x64-msvc": "2.10.0" "@tauri-apps/cli-win32-x64-msvc": "2.11.0"
} }
}, },
"node_modules/@tauri-apps/cli-darwin-arm64": { "node_modules/@tauri-apps/cli-darwin-arm64": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.10.0.tgz", "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.0.tgz",
"integrity": "sha512-avqHD4HRjrMamE/7R/kzJPcAJnZs0IIS+1nkDP5b+TNBn3py7N2aIo9LIpy+VQq0AkN8G5dDpZtOOBkmWt/zjA==", "integrity": "sha512-UfMeDNlgIP252rm/KSTuu8yHatPua5TjtUEUf+jyIzVwBNcIl7Ywkdpfj+e5jVVg3EfCTp+4gwuL1dNpgF8clg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1814,9 +1814,9 @@
} }
}, },
"node_modules/@tauri-apps/cli-darwin-x64": { "node_modules/@tauri-apps/cli-darwin-x64": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.10.0.tgz", "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.0.tgz",
"integrity": "sha512-keDmlvJRStzVFjZTd0xYkBONLtgBC9eMTpmXnBXzsHuawV2q9PvDo2x6D5mhuoMVrJ9QWjgaPKBBCFks4dK71Q==", "integrity": "sha512-lY1+aPlgyMN7vgjtCdQ3+WODfZkebAcxnrCrO0HjqDpKSXieDkrJbimqeaoM4RwhTSrCLRHfVYiYrfE5E131tg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1831,9 +1831,9 @@
} }
}, },
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.10.0.tgz", "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.0.tgz",
"integrity": "sha512-e5u0VfLZsMAC9iHaOEANumgl6lfnJx0Dtjkd8IJpysZ8jp0tJ6wrIkto2OzQgzcYyRCKgX72aKE0PFgZputA8g==", "integrity": "sha512-5uCP0AusgN3NrKC8EpkuJwjek1k8pEffBdugJSpXPey/QGbPEb8vZ542n/giJ2mZPjMSllDkdhG2QIDpBY4PpQ==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -1848,9 +1848,9 @@
} }
}, },
"node_modules/@tauri-apps/cli-linux-arm64-gnu": { "node_modules/@tauri-apps/cli-linux-arm64-gnu": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.10.0.tgz", "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.0.tgz",
"integrity": "sha512-YrYYk2dfmBs5m+OIMCrb+JH/oo+4FtlpcrTCgiFYc7vcs6m3QDd1TTyWu0u01ewsCtK2kOdluhr/zKku+KP7HA==", "integrity": "sha512-loDPqtRHMSbIcrH2VBd4GgHoQlF7jJnrZj7MxA2lj1cixS/jEgMAPFqj83U6Wvjete4HfYplbE/gCpSFifA9jw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1865,9 +1865,9 @@
} }
}, },
"node_modules/@tauri-apps/cli-linux-arm64-musl": { "node_modules/@tauri-apps/cli-linux-arm64-musl": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.10.0.tgz", "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.0.tgz",
"integrity": "sha512-GUoPdVJmrJRIXFfW3Rkt+eGK9ygOdyISACZfC/bCSfOnGt8kNdQIQr5WRH9QUaTVFIwxMlQyV3m+yXYP+xhSVA==", "integrity": "sha512-DtSE8ZBlB9H+L+eHkfZ3myt00EVEyAB3e41juEHoE2qT88fgVlJvyrwa9SZYc/xTwCS9TnmK+R84tpg+ZsAg7Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1882,9 +1882,9 @@
} }
}, },
"node_modules/@tauri-apps/cli-linux-riscv64-gnu": { "node_modules/@tauri-apps/cli-linux-riscv64-gnu": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.10.0.tgz", "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.0.tgz",
"integrity": "sha512-JO7s3TlSxshwsoKNCDkyvsx5gw2QAs/Y2GbR5UE2d5kkU138ATKoPOtxn8G1fFT1aDW4LH0rYAAfBpGkDyJJnw==", "integrity": "sha512-5QdgS4LD+kntClI1aj2JmwjW38LosNXxwCe8viIHEwqYIWuMPdNEIau6/cLogI38Yzx9DnfCPRfEWLyI+5li8Q==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -1899,9 +1899,9 @@
} }
}, },
"node_modules/@tauri-apps/cli-linux-x64-gnu": { "node_modules/@tauri-apps/cli-linux-x64-gnu": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.10.0.tgz", "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.0.tgz",
"integrity": "sha512-Uvh4SUUp4A6DVRSMWjelww0GnZI3PlVy7VS+DRF5napKuIehVjGl9XD0uKoCoxwAQBLctvipyEK+pDXpJeoHng==", "integrity": "sha512-5UynPXo3Zq9khjVdAbD+YogeLltdVUeOah2ioSIM3tu6H7wY9vMy6rgGJhv9r5R8ZXmk9GttMippdqYJWrnLnA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1916,9 +1916,9 @@
} }
}, },
"node_modules/@tauri-apps/cli-linux-x64-musl": { "node_modules/@tauri-apps/cli-linux-x64-musl": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.10.0.tgz", "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.0.tgz",
"integrity": "sha512-AP0KRK6bJuTpQ8kMNWvhIpKUkQJfcPFeba7QshOQZjJ8wOS6emwTN4K5g/d3AbCMo0RRdnZWwu67MlmtJyxC1Q==", "integrity": "sha512-CNz7fHbApz1Zyhhq73jtGn9JqgNEV/lIWnTnUo6h6ujw+mHsTmkLszvJSM8W6JBaDjNpTTFr/RSNoVL5FMwcTg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1933,9 +1933,9 @@
} }
}, },
"node_modules/@tauri-apps/cli-win32-arm64-msvc": { "node_modules/@tauri-apps/cli-win32-arm64-msvc": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.10.0.tgz", "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.0.tgz",
"integrity": "sha512-97DXVU3dJystrq7W41IX+82JEorLNY+3+ECYxvXWqkq7DBN6FsA08x/EFGE8N/b0LTOui9X2dvpGGoeZKKV08g==", "integrity": "sha512-K+br+VXZ+Xx0n/9FdWohpW5Ugq+2FQUpJScqcPl1hTxXfh3fgjYgt4qA2NgrjlJo+zZPNrmUMl+NLvm0ufEqBQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1950,9 +1950,9 @@
} }
}, },
"node_modules/@tauri-apps/cli-win32-ia32-msvc": { "node_modules/@tauri-apps/cli-win32-ia32-msvc": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.10.0.tgz", "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.0.tgz",
"integrity": "sha512-EHyQ1iwrWy1CwMalEm9z2a6L5isQ121pe7FcA2xe4VWMJp+GHSDDGvbTv/OPdkt2Lyr7DAZBpZHM6nvlHXEc4A==", "integrity": "sha512-OFV+s3MLZnd75zl0ZAFU5riMpGK4waUEA8ZDuijDsnkU0btz/gHhqh5jVlOn8thyvgdtT3Xyoxqo099MMifH3g==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -1967,9 +1967,9 @@
} }
}, },
"node_modules/@tauri-apps/cli-win32-x64-msvc": { "node_modules/@tauri-apps/cli-win32-x64-msvc": {
"version": "2.10.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.10.0.tgz", "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.0.tgz",
"integrity": "sha512-NTpyQxkpzGmU6ceWBTY2xRIEaS0ZLbVx1HE1zTA3TY/pV3+cPoPPOs+7YScr4IMzXMtOw7tLw5LEXo5oIG3qaQ==", "integrity": "sha512-AeDTWBd2cOZ6TX133BWsoo+LutG9o0JRcgjMsIfLE13ZugpgCMv/2dJbUiBGeRvbPOGin5A3aYmsArPVV6ZSHQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],