feat: migrate pmg to nx based release automation (#293)

* feat: Migrate release system to Nx with platform-specific npm packages

* add go.work.sum

* fix: CI deprecations, stale action pins, and signal propagation

* fix: update e2e workflows to pnpm 11 and latest action SHAs

* fix: update pmg-e2e.yml to Node 24 with Go and pnpm caching

* fix: resolve E2E failures, remove goreleaser-test, update action SHAs

* fix: restore goreleaser-test (required check)

* fix: escape pnpm workspace detection for yarn/pnpx tests, update action versions
This commit is contained in:
Arunanshu Biswas
2026-05-28 17:22:11 +05:30
committed by GitHub
parent 19b9f2ca1f
commit 1c25395d74
40 changed files with 3205 additions and 698 deletions
+28
View File
@@ -0,0 +1,28 @@
{
"name": "@safedep/pmg-darwin-arm64",
"version": "0.0.0",
"license": "Apache-2.0",
"homepage": "https://safedep.io",
"bugs": {
"url": "https://github.com/safedep/pmg/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/safedep/pmg.git"
},
"publishConfig": {
"access": "public"
},
"os": [
"darwin"
],
"cpu": [
"arm64"
],
"files": [
"bin/**"
],
"bin": {
"pmg": "bin/pmg"
}
}
+28
View File
@@ -0,0 +1,28 @@
{
"name": "@safedep/pmg-darwin-x64",
"version": "0.0.0",
"license": "Apache-2.0",
"homepage": "https://safedep.io",
"bugs": {
"url": "https://github.com/safedep/pmg/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/safedep/pmg.git"
},
"publishConfig": {
"access": "public"
},
"os": [
"darwin"
],
"cpu": [
"x64"
],
"files": [
"bin/**"
],
"bin": {
"pmg": "bin/pmg"
}
}
+28
View File
@@ -0,0 +1,28 @@
{
"name": "@safedep/pmg-linux-arm64",
"version": "0.0.0",
"license": "Apache-2.0",
"homepage": "https://safedep.io",
"bugs": {
"url": "https://github.com/safedep/pmg/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/safedep/pmg.git"
},
"publishConfig": {
"access": "public"
},
"os": [
"linux"
],
"cpu": [
"arm64"
],
"files": [
"bin/**"
],
"bin": {
"pmg": "bin/pmg"
}
}
+28
View File
@@ -0,0 +1,28 @@
{
"name": "@safedep/pmg-linux-x64",
"version": "0.0.0",
"license": "Apache-2.0",
"homepage": "https://safedep.io",
"bugs": {
"url": "https://github.com/safedep/pmg/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/safedep/pmg.git"
},
"publishConfig": {
"access": "public"
},
"os": [
"linux"
],
"cpu": [
"x64"
],
"files": [
"bin/**"
],
"bin": {
"pmg": "bin/pmg"
}
}
+28
View File
@@ -0,0 +1,28 @@
{
"name": "@safedep/pmg-win32-x64",
"version": "0.0.0",
"license": "Apache-2.0",
"homepage": "https://safedep.io",
"bugs": {
"url": "https://github.com/safedep/pmg/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/safedep/pmg.git"
},
"publishConfig": {
"access": "public"
},
"os": [
"win32"
],
"cpu": [
"x64"
],
"files": [
"bin/**"
],
"bin": {
"pmg": "bin/pmg.exe"
}
}
+39
View File
@@ -0,0 +1,39 @@
{
"name": "@safedep/pmg",
"version": "0.0.0",
"description": "PMG - Package Manager Guard: protect developers from malicious packages",
"license": "Apache-2.0",
"keywords": ["security", "supply-chain", "packages", "safedep", "pmg"],
"engines": { "node": ">=18" },
"repository": {
"type": "git",
"url": "git+https://github.com/safedep/pmg.git"
},
"homepage": "https://safedep.io",
"bugs": { "url": "https://github.com/safedep/pmg/issues" },
"publishConfig": { "access": "public" },
"type": "module",
"bin": {
"pmg": "dist/bin.cjs"
},
"files": [
"dist/**"
],
"optionalDependencies": {
"@safedep/pmg-linux-x64": "workspace:*",
"@safedep/pmg-linux-arm64": "workspace:*",
"@safedep/pmg-darwin-x64": "workspace:*",
"@safedep/pmg-darwin-arm64": "workspace:*",
"@safedep/pmg-win32-x64": "workspace:*"
},
"scripts": {
"prepack": "cp ../../README.md README.md",
"build": "tsdown",
"typecheck": "tsc -p tsconfig.json --noEmit"
},
"devDependencies": {
"@types/node": "25.9.1",
"tsdown": "0.22.0",
"typescript": "6.0.3"
}
}
+35
View File
@@ -0,0 +1,35 @@
{
"name": "@safedep/pmg",
"root": "packages/pmg",
"targets": {
"build": {
"executor": "nx:run-commands",
"dependsOn": [{"projects": "sync-binaries", "target": "run"}],
"options": {
"command": "pnpm run build",
"cwd": "{projectRoot}"
},
"inputs": ["tsPackageSources", "{projectRoot}/tsdown.config.ts"],
"outputs": ["{projectRoot}/dist"]
},
"build-release": {
"executor": "nx:run-commands",
"dependsOn": [{"projects": "sync-binaries", "target": "run-release"}],
"options": {
"command": "pnpm run build",
"cwd": "{projectRoot}"
},
"inputs": ["tsPackageSources", "{projectRoot}/tsdown.config.ts"],
"outputs": ["{projectRoot}/dist"],
"cache": false
},
"typecheck": {
"executor": "nx:run-commands",
"options": {
"command": "pnpm run typecheck",
"cwd": "{projectRoot}"
},
"inputs": ["tsPackageSources"]
}
}
}
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env node
import { createRequire } from "node:module";
import { dirname, join } from "node:path";
import { existsSync } from "node:fs";
import { spawn } from "node:child_process";
const require = createRequire(import.meta.url);
function pkgNameForHost(): string {
const platform = process.platform; // linux | darwin | win32
const arch = process.arch; // x64 | arm64
return `@safedep/pmg-${platform}-${arch}`;
}
function findBinaryPath(pkgName: string): string {
const pkgJsonPath = require.resolve(`${pkgName}/package.json`);
const pkgRoot = dirname(pkgJsonPath);
const exe = process.platform === "win32" ? "pmg.exe" : "pmg";
const p = join(pkgRoot, "bin", exe);
if (!existsSync(p)) {
throw new Error(
`Binary not found at ${p}. The platform package "${pkgName}" is installed but does not contain bin/${exe}.`
);
}
return p;
}
function main() {
const pkgName = pkgNameForHost();
let binPath: string;
try {
binPath = findBinaryPath(pkgName);
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
console.error(
[
"Failed to locate the platform binary.",
`Host: ${process.platform}/${process.arch}`,
`Expected platform package: ${pkgName}`,
msg,
"",
"Common causes:",
"- optionalDependencies were omitted during install",
"- this platform/arch is not published yet",
"- the platform package was published without the binary in bin/",
].join("\n")
);
process.exit(1);
}
const child = spawn(binPath, process.argv.slice(2), { stdio: "inherit" });
child.on("exit", (code: number | null, signal: string | null) => {
if (signal) {
process.kill(process.pid, signal as NodeJS.Signals);
return;
}
process.exit(code ?? 1);
});
child.on("error", (error: Error) => {
console.error(`Failed to spawn the binary: ${error}`);
process.exit(1);
});
}
main();
+11
View File
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"types": ["node"]
},
"include": ["src/**/*"]
}
+8
View File
@@ -0,0 +1,8 @@
import { defineConfig } from "tsdown";
export default defineConfig({
entry: ["src/bin.ts"],
format: ["cjs"],
clean: true,
minify: true,
});