From ee3b6dd6ae2ff2323463815336d770ca60d43e53 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Fri, 9 Jan 2026 17:48:32 +0000 Subject: [PATCH] fix(ci): add Gitea release asset uploader and switch release workflow to use it; bump package and daemon versions to 0.3.4 --- .gitea/release-upload.ts | 90 ++++++++++++++++++ .gitea/workflows/release.yml | 17 ++-- changelog.md | 8 ++ ecoos_daemon/ts/version.ts | 2 +- .../includes.chroot/opt/eco/bin/eco-daemon | Bin 86979372 -> 86979372 bytes package.json | 2 +- 6 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 .gitea/release-upload.ts diff --git a/.gitea/release-upload.ts b/.gitea/release-upload.ts new file mode 100644 index 0000000..a8f6bfe --- /dev/null +++ b/.gitea/release-upload.ts @@ -0,0 +1,90 @@ +/** + * Release asset uploader for Gitea + * Streams large files without loading them into memory (bypasses curl's 2GB multipart limit) + * + * Usage: GITEA_TOKEN=xxx RELEASE_ID=123 GITEA_REPO=owner/repo tsx release-upload.ts + */ + +import * as fs from 'fs'; +import * as path from 'path'; +import * as https from 'https'; + +const token = process.env.GITEA_TOKEN; +const releaseId = process.env.RELEASE_ID; +const repo = process.env.GITEA_REPO; + +if (!token || !releaseId || !repo) { + console.error('Missing required env vars: GITEA_TOKEN, RELEASE_ID, GITEA_REPO'); + process.exit(1); +} + +const boundary = '----FormBoundary' + Date.now().toString(16); + +async function uploadFile(filepath: string): Promise { + const filename = path.basename(filepath); + const stats = fs.statSync(filepath); + console.log(`Uploading ${filename} (${stats.size} bytes)...`); + + const header = Buffer.from( + `--${boundary}\r\n` + + `Content-Disposition: form-data; name="attachment"; filename="${filename}"\r\n` + + `Content-Type: application/octet-stream\r\n\r\n` + ); + const footer = Buffer.from(`\r\n--${boundary}--\r\n`); + const contentLength = header.length + stats.size + footer.length; + + return new Promise((resolve, reject) => { + const req = https.request({ + hostname: 'code.foss.global', + path: `/api/v1/repos/${repo}/releases/${releaseId}/assets?name=${encodeURIComponent(filename)}`, + method: 'POST', + headers: { + 'Authorization': `token ${token}`, + 'Content-Type': `multipart/form-data; boundary=${boundary}`, + 'Content-Length': contentLength + } + }, (res) => { + let data = ''; + res.on('data', chunk => data += chunk); + res.on('end', () => { + console.log(data); + if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) { + console.log(`✓ ${filename} uploaded successfully`); + resolve(); + } else { + reject(new Error(`Upload failed: ${res.statusCode} ${data}`)); + } + }); + }); + + req.on('error', reject); + + // Stream: write header, pipe file, write footer + req.write(header); + const stream = fs.createReadStream(filepath); + stream.on('error', reject); + stream.on('end', () => { + req.write(footer); + req.end(); + }); + stream.pipe(req, { end: false }); + }); +} + +async function main() { + const distDir = 'dist'; + const files = fs.readdirSync(distDir) + .map(f => path.join(distDir, f)) + .filter(f => fs.statSync(f).isFile()); + + for (const file of files) { + await uploadFile(file); + } + + console.log('All assets uploaded successfully'); +} + +main().catch(err => { + console.error(err); + process.exit(1); +}); diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 83e8be8..46f8f0b 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -75,16 +75,13 @@ jobs: echo "Created release with ID: $RELEASE_ID" - # Upload assets - for asset in dist/*; do - filename=$(basename "$asset") - echo "Uploading $filename..." - curl -X POST -s \ - -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - -H "Content-Type: application/octet-stream" \ - -T "$asset" \ - "https://code.foss.global/api/v1/repos/${{ gitea.repository }}/releases/$RELEASE_ID/assets?name=$filename" - done + # Upload assets using TypeScript (curl has 2GB multipart limit) + pnpm install -g tsx + + GITEA_TOKEN="${{ secrets.GITHUB_TOKEN }}" \ + GITEA_REPO="${{ gitea.repository }}" \ + RELEASE_ID="$RELEASE_ID" \ + tsx .gitea/release-upload.ts - name: Cleanup old releases (keep 3 latest) run: | diff --git a/changelog.md b/changelog.md index 488feeb..6b84a3b 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,13 @@ # Changelog +## 2026-01-09 - 0.3.5 - fix(ci) +add Gitea release asset uploader and switch release workflow to use it; bump package and daemon versions to 0.3.4 + +- Add .gitea/release-upload.ts: streams assets to Gitea to avoid curl's 2GB multipart limit +- Update CI workflow (.gitea/workflows/release.yml) to run the TypeScript uploader via tsx +- Bump package.json and ecoos_daemon/ts/version.ts to 0.3.4 +- Update bundled eco-daemon binary in isobuild/config/includes.chroot/opt/eco/bin/ + ## 2026-01-09 - 0.3.2 - fix(release) bump package and daemon to v0.3.1, add project README, and fix Gitea release upload flag diff --git a/ecoos_daemon/ts/version.ts b/ecoos_daemon/ts/version.ts index 767a57d..5f0ba60 100644 --- a/ecoos_daemon/ts/version.ts +++ b/ecoos_daemon/ts/version.ts @@ -1 +1 @@ -export const VERSION = "0.3.1"; +export const VERSION = "0.3.4"; diff --git a/isobuild/config/includes.chroot/opt/eco/bin/eco-daemon b/isobuild/config/includes.chroot/opt/eco/bin/eco-daemon index e26d9128917d48f7e3e80cc835ff73830401e8c4..b7bcda28a414a3d4b7729f17c8ae8ad99c3f4451 100755 GIT binary patch delta 3784 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 mrKYCVs$Das=A_9xD<%K0a