Skip to content

Commit 57ed166

Browse files
committed
perf(publish): optimize CLI build and consolidate platform definitions
Changes: - Build CLI bundle once in dedicated job, share via artifact (saves ~7-8 minutes by avoiding 8 redundant builds) - Add dynamic matrix generation from PLATFORM_CONFIGS - Centralize platform definitions in platform-targets.mjs - Add error handling (set -euo pipefail) to bash loops - Add helper scripts for workflow: get-platform-matrix.mjs, get-platform-targets.mjs PLATFORM_CONFIGS is now the single source of truth for: - Platform/arch combinations - GitHub Actions runners - Binary extensions - CPU architectures - Platform descriptions
1 parent 8ee9d4b commit 57ed166

File tree

7 files changed

+204
-74
lines changed

7 files changed

+204
-74
lines changed

.github/workflows/publish.yml

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,56 @@ env:
3636
BUILD_MODE: prod
3737

3838
jobs:
39+
# Build CLI bundle once (platform-agnostic JS) and generate platform matrix.
40+
build-cli:
41+
if: ${{ inputs.publish-binaries }}
42+
name: Build CLI bundle
43+
runs-on: ubuntu-latest
44+
permissions:
45+
contents: read
46+
outputs:
47+
matrix: ${{ steps.matrix.outputs.matrix }}
48+
49+
steps:
50+
- uses: actions/checkout@v4
51+
with:
52+
persist-credentials: false
53+
54+
- uses: actions/setup-node@v4
55+
with:
56+
node-version-file: .node-version
57+
58+
- uses: pnpm/action-setup@v4
59+
60+
- run: pnpm install --frozen-lockfile
61+
62+
- name: Build CLI
63+
run: pnpm --filter @socketsecurity/cli run build
64+
65+
- name: Generate platform matrix
66+
id: matrix
67+
run: |
68+
MATRIX=$(node scripts/get-platform-matrix.mjs)
69+
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT
70+
71+
- name: Upload CLI bundle
72+
uses: actions/upload-artifact@v4
73+
with:
74+
name: cli-bundle
75+
path: packages/cli/build/cli.js
76+
retention-days: 1
77+
3978
# Build SEA binaries for all platforms (only if publishing binaries).
4079
build-binaries:
4180
if: ${{ inputs.publish-binaries }}
81+
needs: [build-cli]
4282
name: Build ${{ matrix.platform }}-${{ matrix.arch }}${{ matrix.libc && '-musl' || '' }}
4383
runs-on: ${{ matrix.runner }}
4484
permissions:
4585
contents: read
4686
strategy:
4787
fail-fast: false
48-
matrix:
49-
include:
50-
- { runner: ubuntu-latest, platform: linux, arch: x64 }
51-
- { runner: ubuntu-latest, platform: linux, arch: arm64 }
52-
- { runner: ubuntu-latest, platform: linux, arch: x64, libc: musl }
53-
- { runner: ubuntu-latest, platform: linux, arch: arm64, libc: musl }
54-
- { runner: macos-latest, platform: darwin, arch: x64 }
55-
- { runner: macos-latest, platform: darwin, arch: arm64 }
56-
- { runner: windows-latest, platform: win32, arch: x64 }
57-
- { runner: windows-latest, platform: win32, arch: arm64 }
88+
matrix: ${{ fromJson(needs.build-cli.outputs.matrix) }}
5889

5990
steps:
6091
- uses: actions/checkout@v4
@@ -70,8 +101,11 @@ jobs:
70101

71102
- run: pnpm install --frozen-lockfile
72103

73-
- name: Build CLI
74-
run: pnpm --filter @socketsecurity/cli run build
104+
- name: Download CLI bundle
105+
uses: actions/download-artifact@v4
106+
with:
107+
name: cli-bundle
108+
path: packages/cli/build
75109

76110
- name: Build SEA binary
77111
shell: bash
@@ -95,8 +129,8 @@ jobs:
95129
# Publish all packages.
96130
publish:
97131
name: Publish packages
98-
needs: [build-binaries]
99-
if: ${{ always() && (needs.build-binaries.result == 'success' || needs.build-binaries.result == 'skipped') }}
132+
needs: [build-cli, build-binaries]
133+
if: ${{ always() && (needs.build-cli.result == 'success' || needs.build-cli.result == 'skipped') && (needs.build-binaries.result == 'success' || needs.build-binaries.result == 'skipped') }}
100134
runs-on: ubuntu-latest
101135
permissions:
102136
contents: read
@@ -139,7 +173,11 @@ jobs:
139173
env:
140174
VERSION: ${{ steps.version.outputs.version }}
141175
run: |
142-
PLATFORMS=("linux-x64" "linux-arm64" "linux-x64-musl" "linux-arm64-musl" "darwin-x64" "darwin-arm64" "win32-x64" "win32-arm64")
176+
set -euo pipefail
177+
178+
# Get platform targets from single source of truth.
179+
PLATFORMS_STR=$(node scripts/get-platform-targets.mjs)
180+
read -ra PLATFORMS <<< "$PLATFORMS_STR"
143181
144182
for target in "${PLATFORMS[@]}"; do
145183
echo "::group::Publishing @socketbin/cli-${target}"

packages/build-infra/lib/platform-targets.mjs

Lines changed: 108 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,108 @@
11
/**
22
* @fileoverview Shared platform target utilities for SEA builds.
33
* Provides constants and parsing functions for platform/arch/libc combinations.
4+
* This is the single source of truth for all platform definitions.
45
*/
56

7+
/**
8+
* Complete platform configuration with all metadata.
9+
* This is the authoritative source for platform definitions.
10+
* @type {ReadonlyArray<{
11+
* platform: string,
12+
* arch: string,
13+
* libc?: string,
14+
* runner: string,
15+
* cpu: string,
16+
* os: string,
17+
* binExt: string,
18+
* description: string
19+
* }>}
20+
*/
21+
export const PLATFORM_CONFIGS = Object.freeze([
22+
{
23+
arch: 'arm64',
24+
binExt: '',
25+
cpu: 'arm64',
26+
description: 'macOS ARM64 (Apple Silicon)',
27+
os: 'darwin',
28+
platform: 'darwin',
29+
runner: 'macos-latest',
30+
},
31+
{
32+
arch: 'x64',
33+
binExt: '',
34+
cpu: 'x64',
35+
description: 'macOS x64 (Intel)',
36+
os: 'darwin',
37+
platform: 'darwin',
38+
runner: 'macos-latest',
39+
},
40+
{
41+
arch: 'arm64',
42+
binExt: '',
43+
cpu: 'arm64',
44+
description: 'Linux ARM64 (glibc)',
45+
os: 'linux',
46+
platform: 'linux',
47+
runner: 'ubuntu-latest',
48+
},
49+
{
50+
arch: 'arm64',
51+
binExt: '',
52+
cpu: 'arm64',
53+
description: 'Linux ARM64 (musl/Alpine)',
54+
libc: 'musl',
55+
os: 'linux',
56+
platform: 'linux',
57+
runner: 'ubuntu-latest',
58+
},
59+
{
60+
arch: 'x64',
61+
binExt: '',
62+
cpu: 'x64',
63+
description: 'Linux x64 (glibc)',
64+
os: 'linux',
65+
platform: 'linux',
66+
runner: 'ubuntu-latest',
67+
},
68+
{
69+
arch: 'x64',
70+
binExt: '',
71+
cpu: 'x64',
72+
description: 'Linux x64 (musl/Alpine)',
73+
libc: 'musl',
74+
os: 'linux',
75+
platform: 'linux',
76+
runner: 'ubuntu-latest',
77+
},
78+
{
79+
arch: 'arm64',
80+
binExt: '.exe',
81+
cpu: 'arm64',
82+
description: 'Windows ARM64',
83+
os: 'win32',
84+
platform: 'win32',
85+
runner: 'windows-latest',
86+
},
87+
{
88+
arch: 'x64',
89+
binExt: '.exe',
90+
cpu: 'x64',
91+
description: 'Windows x64',
92+
os: 'win32',
93+
platform: 'win32',
94+
runner: 'windows-latest',
95+
},
96+
])
97+
698
/**
799
* Valid platform targets for SEA builds.
8100
* Format: <platform>-<arch>[-musl]
101+
* Derived from PLATFORM_CONFIGS.
9102
*/
10-
export const PLATFORM_TARGETS = [
11-
'darwin-arm64',
12-
'darwin-x64',
13-
'linux-arm64',
14-
'linux-arm64-musl',
15-
'linux-x64',
16-
'linux-x64-musl',
17-
'win32-arm64',
18-
'win32-x64',
19-
]
103+
export const PLATFORM_TARGETS = PLATFORM_CONFIGS.map(
104+
c => `${c.platform}-${c.arch}${c.libc ? `-${c.libc}` : ''}`,
105+
)
20106

21107
/**
22108
* Valid platforms.
@@ -92,6 +178,18 @@ export function isPlatformTarget(target) {
92178
return PLATFORM_TARGETS.includes(target)
93179
}
94180

181+
/**
182+
* Get the full platform config for a target string.
183+
*
184+
* @param {string} target - Target string (e.g., "darwin-arm64" or "linux-x64-musl").
185+
* @returns {typeof PLATFORM_CONFIGS[number] | undefined} Full platform config or undefined.
186+
*/
187+
export function getPlatformConfig(target) {
188+
return PLATFORM_CONFIGS.find(
189+
c => `${c.platform}-${c.arch}${c.libc ? `-${c.libc}` : ''}` === target,
190+
)
191+
}
192+
95193
/**
96194
* Format platform info back into a target string.
97195
*

packages/package-builder/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
},
1616
"dependencies": {
1717
"@socketsecurity/lib": "catalog:",
18+
"build-infra": "workspace:*",
1819
"handlebars": "^4.7.8"
1920
},
2021
"engines": {

packages/package-builder/scripts/generate-socketbin-packages.mjs

Lines changed: 4 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,69 +10,24 @@
1010
import { existsSync, promises as fs } from 'node:fs'
1111
import path from 'node:path'
1212

13+
import { PLATFORM_CONFIGS } from 'build-infra/lib/platform-targets'
1314
import { getDefaultLogger } from '@socketsecurity/lib/logger'
1415

1516
import { getSocketbinPackageDir, SOCKETBIN_TEMPLATE_DIR } from './paths.mjs'
1617
import { processTemplate } from './utils.mjs'
1718

1819
const logger = getDefaultLogger()
1920

20-
const PLATFORM_DESCRIPTIONS = {
21-
__proto__: null,
22-
'darwin-arm64': 'macOS ARM64 (Apple Silicon)',
23-
'darwin-x64': 'macOS x64 (Intel)',
24-
'linux-arm64': 'Linux ARM64 (glibc)',
25-
'linux-arm64-musl': 'Linux ARM64 (musl/Alpine)',
26-
'linux-x64': 'Linux x64 (glibc)',
27-
'linux-x64-musl': 'Linux x64 (musl/Alpine)',
28-
'win32-arm64': 'Windows ARM64',
29-
'win32-x64': 'Windows x64',
30-
}
31-
32-
const PACKAGES = [
33-
{ arch: 'arm64', binExt: '', cpu: 'arm64', os: 'darwin', platform: 'darwin' },
34-
{ arch: 'x64', binExt: '', cpu: 'x64', os: 'darwin', platform: 'darwin' },
35-
{ arch: 'arm64', binExt: '', cpu: 'arm64', os: 'linux', platform: 'linux' },
36-
{
37-
arch: 'arm64',
38-
binExt: '',
39-
cpu: 'arm64',
40-
libc: 'musl',
41-
os: 'linux',
42-
platform: 'linux',
43-
},
44-
{ arch: 'x64', binExt: '', cpu: 'x64', os: 'linux', platform: 'linux' },
45-
{
46-
arch: 'x64',
47-
binExt: '',
48-
cpu: 'x64',
49-
libc: 'musl',
50-
os: 'linux',
51-
platform: 'linux',
52-
},
53-
{
54-
arch: 'arm64',
55-
binExt: '.exe',
56-
cpu: 'arm64',
57-
os: 'win32',
58-
platform: 'win32',
59-
},
60-
{ arch: 'x64', binExt: '.exe', cpu: 'x64', os: 'win32', platform: 'win32' },
61-
]
62-
6321
/**
6422
* Generate a single socketbin package.
6523
*/
6624
async function generatePackage(config) {
67-
const { arch, binExt, cpu, libc, os, platform } = config
25+
const { arch, binExt, cpu, description, libc, os, platform } = config
6826
const muslSuffix = libc === 'musl' ? '-musl' : ''
6927
const packageName = `socketbin-cli-${platform}-${arch}${muslSuffix}`
7028
const packagePath = getSocketbinPackageDir(platform, arch, libc)
7129
const templatePath = SOCKETBIN_TEMPLATE_DIR
7230

73-
const descKey = `${platform}-${arch}${muslSuffix}`
74-
const description = PLATFORM_DESCRIPTIONS[descKey] || `${platform} ${arch}`
75-
7631
// Template context for Handlebars.
7732
const context = {
7833
ARCH: arch,
@@ -140,12 +95,12 @@ async function main() {
14095
}
14196

14297
// Generate all packages.
143-
for (const config of PACKAGES) {
98+
for (const config of PLATFORM_CONFIGS) {
14499
await generatePackage(config)
145100
}
146101

147102
logger.log('')
148-
logger.success(`Generated ${PACKAGES.length} socketbin packages`)
103+
logger.success(`Generated ${PLATFORM_CONFIGS.length} socketbin packages`)
149104
logger.log('')
150105
}
151106

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/get-platform-matrix.mjs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Output platform matrix JSON for GitHub Actions.
4+
* Used by publish workflow to generate dynamic matrix.
5+
*
6+
* Usage:
7+
* node scripts/get-platform-matrix.mjs
8+
* # Outputs: {"include":[...]}
9+
*/
10+
11+
import { PLATFORM_CONFIGS } from '../packages/build-infra/lib/platform-targets.mjs'
12+
13+
const matrix = {
14+
include: PLATFORM_CONFIGS.map(c => ({
15+
arch: c.arch,
16+
libc: c.libc ?? null,
17+
platform: c.platform,
18+
runner: c.runner,
19+
})),
20+
}
21+
22+
console.log(JSON.stringify(matrix))

scripts/get-platform-targets.mjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Output platform targets for shell scripts.
4+
* Used by publish workflow to iterate over platforms.
5+
*
6+
* Usage:
7+
* node scripts/get-platform-targets.mjs
8+
* # Outputs space-separated: linux-x64 linux-arm64 ...
9+
*/
10+
11+
import { PLATFORM_TARGETS } from '../packages/build-infra/lib/platform-targets.mjs'
12+
13+
console.log(PLATFORM_TARGETS.join(' '))

0 commit comments

Comments
 (0)