From 6af62aa093336d446b9ef462387b938abc8d22ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=A4=A7=E7=8C=AB?= <16399091+binaricat@users.noreply.github.com> Date: Tue, 9 Jun 2026 21:07:56 +0800 Subject: [PATCH] Add Arch pacman Linux package (#1344) --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/scripts/generate-release-note.js | 11 ++++++-- .github/workflows/build.yml | 8 ++++++ electron-builder.config.cjs | 2 +- scripts/electron-builder-config.test.cjs | 8 ++++++ scripts/generate-release-note.test.cjs | 36 ++++++++++++++++++++++++ scripts/github-workflow-build.test.cjs | 22 +++++++++++++++ 7 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 scripts/generate-release-note.test.cjs diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index a4f7dbaa..e97a74b7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -34,7 +34,7 @@ body: attributes: label: How did you install Netcatty? options: - - GitHub Release (.dmg / .exe / .AppImage / .deb) + - GitHub Release (.dmg / .exe / .AppImage / .deb / .rpm / .pacman) - Homebrew - Built from source (npm run dev / pack) - Other diff --git a/.github/scripts/generate-release-note.js b/.github/scripts/generate-release-note.js index 7a423c07..a706d550 100644 --- a/.github/scripts/generate-release-note.js +++ b/.github/scripts/generate-release-note.js @@ -50,6 +50,7 @@ const baseUrl = `https://github.com/${repo}/releases/download/${tag}`; // - AppImage: x64 -> x86_64, arm64 -> arm64 // - deb: x64 -> amd64, arm64 -> arm64 // - rpm: x64 -> x86_64, arm64 -> aarch64 +// - pacman: x64 -> x64, arm64 -> aarch64 const files = { mac: { arm64: `Netcatty-${version}-mac-arm64.dmg`, @@ -70,6 +71,10 @@ const files = { rpm: { x64: `Netcatty-${version}-linux-x86_64.rpm`, arm64: `Netcatty-${version}-linux-aarch64.rpm` + }, + pacman: { + x64: `Netcatty-${version}-linux-x64.pacman`, + arm64: `Netcatty-${version}-linux-aarch64.pacman` } } }; @@ -88,7 +93,9 @@ const badges = { deb_x64: `[![DebPackage x64](https://img.shields.io/badge/DebPackage-x64-A80030?style=flat-square&logo=debian)](${baseUrl}/${files.linux.deb.x64})`, deb_arm64: `[![DebPackage arm64](https://img.shields.io/badge/DebPackage-arm64-A80030?style=flat-square&logo=debian)](${baseUrl}/${files.linux.deb.arm64})`, rpm_x64: `[![RpmPackage x64](https://img.shields.io/badge/RpmPackage-x64-CC0000?style=flat-square&logo=redhat)](${baseUrl}/${files.linux.rpm.x64})`, - rpm_arm64: `[![RpmPackage arm64](https://img.shields.io/badge/RpmPackage-arm64-CC0000?style=flat-square&logo=redhat)](${baseUrl}/${files.linux.rpm.arm64})` + rpm_arm64: `[![RpmPackage arm64](https://img.shields.io/badge/RpmPackage-arm64-CC0000?style=flat-square&logo=redhat)](${baseUrl}/${files.linux.rpm.arm64})`, + pacman_x64: `[![ArchPackage x64](https://img.shields.io/badge/ArchPackage-x64-1793D1?style=flat-square&logo=archlinux)](${baseUrl}/${files.linux.pacman.x64})`, + pacman_arm64: `[![ArchPackage arm64](https://img.shields.io/badge/ArchPackage-arm64-1793D1?style=flat-square&logo=archlinux)](${baseUrl}/${files.linux.pacman.arm64})` } }; @@ -99,7 +106,7 @@ const content = ` | :--- | :--- | | **Windows** | ${badges.win.setup_x64} | | **macOS** | ${badges.mac.apple_silicon} ${badges.mac.intel} | -| **Linux** | ${badges.linux.appimage_x64} ${badges.linux.deb_x64} ${badges.linux.rpm_x64}
${badges.linux.appimage_arm64} ${badges.linux.deb_arm64} ${badges.linux.rpm_arm64} | +| **Linux** | ${badges.linux.appimage_x64} ${badges.linux.deb_x64} ${badges.linux.rpm_x64} ${badges.linux.pacman_x64}
${badges.linux.appimage_arm64} ${badges.linux.deb_arm64} ${badges.linux.rpm_arm64} ${badges.linux.pacman_arm64} | `; fs.writeFileSync('release_notes.md', content); diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0a9e9c35..8d7b4dc2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -348,6 +348,7 @@ jobs: release/*.AppImage release/*.deb release/*.rpm + release/*.pacman release/*.tar.gz release/*.yml release/*.blockmap @@ -410,6 +411,9 @@ jobs: - name: Install deps run: npm ci + - name: Install pacman packaging dependencies + run: sudo apt-get update && sudo apt-get install -y libarchive-tools + - name: Set version shell: bash run: | @@ -457,6 +461,7 @@ jobs: release/*.AppImage release/*.deb release/*.rpm + release/*.pacman release/*.yml release/*.blockmap if-no-files-found: ignore @@ -510,6 +515,7 @@ jobs: run: | apt-get update apt-get install -y curl build-essential python3 git libfuse2 file rpm \ + libarchive-tools \ libglib2.0-0 libgtk-3-0 libnss3 libxss1 libxtst6 libasound2 \ libatk-bridge2.0-0 libdrm2 libgbm1 libx11-xcb1 libxcb-dri3-0 curl -fsSL https://deb.nodesource.com/setup_22.x | bash - @@ -568,6 +574,7 @@ jobs: release/*.AppImage release/*.deb release/*.rpm + release/*.pacman release/*.yml release/*.blockmap if-no-files-found: ignore @@ -673,6 +680,7 @@ jobs: artifacts/*.AppImage artifacts/*.deb artifacts/*.rpm + artifacts/*.pacman artifacts/*.yml artifacts/*.blockmap generate_release_notes: true diff --git a/electron-builder.config.cjs b/electron-builder.config.cjs index 21e59516..9a60277d 100644 --- a/electron-builder.config.cjs +++ b/electron-builder.config.cjs @@ -154,7 +154,7 @@ module.exports = { // installs only hicolor/1024x1024 and launchers miss the icon (#274, // #1340). Do NOT set linux.icon to a single 1024px PNG either. icon: 'icons', - target: ['AppImage', 'deb', 'rpm'], + target: ['AppImage', 'deb', 'rpm', 'pacman'], category: 'Development', extraResources: [...moshExtraResources('linux'), ...etExtraResources('linux')] }, diff --git a/scripts/electron-builder-config.test.cjs b/scripts/electron-builder-config.test.cjs index 4614c273..1fde2da2 100644 --- a/scripts/electron-builder-config.test.cjs +++ b/scripts/electron-builder-config.test.cjs @@ -87,3 +87,11 @@ test("linux packaging uses multi-size build/icons instead of a single 1024px ove `expected standard hicolor sizes, got: ${sizes.join(", ")}`, ); }); + +test("linux packaging includes an Arch Linux pacman package target", () => { + assert.deepEqual( + config.linux.target, + ["AppImage", "deb", "rpm", "pacman"], + "linux package builds must publish AppImage, Debian, RPM, and Arch pacman artifacts", + ); +}); diff --git a/scripts/generate-release-note.test.cjs b/scripts/generate-release-note.test.cjs new file mode 100644 index 00000000..9ccf4d8a --- /dev/null +++ b/scripts/generate-release-note.test.cjs @@ -0,0 +1,36 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); +const { execFileSync } = require("node:child_process"); + +test("release notes include Arch pacman downloads for x64 and arm64", (t) => { + const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "netcatty-release-note-")); + t.after(() => fs.rmSync(tmp, { recursive: true, force: true })); + + const script = path.join(__dirname, "..", ".github", "scripts", "generate-release-note.js"); + execFileSync(process.execPath, [script], { + cwd: tmp, + env: { + ...process.env, + VERSION: "1.2.3", + GITHUB_REF_NAME: "v1.2.3", + GITHUB_REPOSITORY: "binaricat/Netcatty", + GITHUB_SHA: "0123456789abcdef", + }, + stdio: "pipe", + }); + + const notes = fs.readFileSync(path.join(tmp, "release_notes.md"), "utf8"); + assert.match(notes, /ArchPackage x64/); + assert.match(notes, /ArchPackage arm64/); + assert.match( + notes, + /https:\/\/github\.com\/binaricat\/Netcatty\/releases\/download\/v1\.2\.3\/Netcatty-1\.2\.3-linux-x64\.pacman/, + ); + assert.match( + notes, + /https:\/\/github\.com\/binaricat\/Netcatty\/releases\/download\/v1\.2\.3\/Netcatty-1\.2\.3-linux-aarch64\.pacman/, + ); +}); diff --git a/scripts/github-workflow-build.test.cjs b/scripts/github-workflow-build.test.cjs index 279ff1fb..5c09dae6 100644 --- a/scripts/github-workflow-build.test.cjs +++ b/scripts/github-workflow-build.test.cjs @@ -22,3 +22,25 @@ test("build workflow no longer installs removed legacy agent binaries", () => { ); } }); + +test("build workflow uploads and releases Arch pacman artifacts", () => { + const releaseUploadPatterns = buildWorkflow.match(/release\/\*\.pacman/g) ?? []; + assert.equal( + releaseUploadPatterns.length, + 3, + "mac/windows aggregate upload plus both Linux jobs must include release/*.pacman", + ); + assert.ok( + buildWorkflow.includes("artifacts/*.pacman"), + "GitHub release file list must include downloaded pacman artifacts", + ); +}); + +test("build workflow installs bsdtar for Arch pacman packaging", () => { + const installMentions = buildWorkflow.match(/libarchive-tools/g) ?? []; + assert.equal( + installMentions.length, + 2, + "both Linux package jobs must install libarchive-tools for pacman metadata generation", + ); +});