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: `[](${baseUrl}/${files.linux.deb.x64})`,
deb_arm64: `[](${baseUrl}/${files.linux.deb.arm64})`,
rpm_x64: `[](${baseUrl}/${files.linux.rpm.x64})`,
- rpm_arm64: `[](${baseUrl}/${files.linux.rpm.arm64})`
+ rpm_arm64: `[](${baseUrl}/${files.linux.rpm.arm64})`,
+ pacman_x64: `[](${baseUrl}/${files.linux.pacman.x64})`,
+ pacman_arm64: `[](${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",
+ );
+});