@leverege/build-tools 2.106.5 → 2.107.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -251,7 +251,7 @@ repo-panopticon --limit 40 @srv/* # cap displayed rows (default 80)
|
|
|
251
251
|
repo-panopticon --concurrency 10 @srv/* # increase parallelism (default 5)
|
|
252
252
|
```
|
|
253
253
|
Columns: `mgr` (npm/yrn) · `pkg` (package.json version) · `git` (latest semver tag) ·
|
|
254
|
-
`scop` (package scope) · `cir` (
|
|
254
|
+
`scop` (package scope) · `cir` (CI status — ✘ missing · L legacy · 1 orb v1 · 2 orb v2 · ★ orb v2 + GHA ci.yml) ·
|
|
255
255
|
`ESM` (`"type":"module"`) · `har` (.har hooks directory) · `lnt` (ESLint major version) ·
|
|
256
256
|
`bbl` (Babel presence). Repo name shown in orange when dirty or sync failed.
|
|
257
257
|
|
|
@@ -282,6 +282,14 @@ the appropriate template. Preserves existing customizations.
|
|
|
282
282
|
circle-orb-it [--dry-run] [--debug]
|
|
283
283
|
```
|
|
284
284
|
|
|
285
|
+
**`github-actions-it`** — Installs or updates GitHub Actions CI configuration for a
|
|
286
|
+
Leverege library repository. Reads existing `.circleci/config.yml` to preserve settings
|
|
287
|
+
(coverage threshold, cache config, GCP context) when migrating from CircleCI. Generates
|
|
288
|
+
`.github/workflows/ci.yml` using the shared `library-ci.yml` reusable workflow.
|
|
289
|
+
```bash
|
|
290
|
+
github-actions-it [--dry-run] [--debug]
|
|
291
|
+
```
|
|
292
|
+
|
|
285
293
|
**`send-to-slack`** — Sends messages to a Slack channel, retrieving the webhook URL
|
|
286
294
|
from GCP Secret Manager.
|
|
287
295
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leverege/build-tools",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.107.0",
|
|
4
4
|
"description": "A collection of build / support tools for Leverege developers",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
"url": "git+ssh://git@bitbucket.org/leverege/build-tools.git"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"clean": "rm -rf lib",
|
|
12
11
|
"lint": "eslint",
|
|
12
|
+
"lint-fix": "eslint --fix",
|
|
13
|
+
"prepack": "npm exec prepack",
|
|
13
14
|
"prepare": "[ $SKIP_PREPARE ] && exit 0 || ./src/hook-and-release.mjs",
|
|
14
15
|
"test": "mocha -t 60000 --exit 'test/**/!(*e2e*).mjs'",
|
|
15
|
-
"test-all": "mocha -t 60000 --exit 'test/**/**.mjs'"
|
|
16
|
-
"prepack": "npm exec prepack"
|
|
16
|
+
"test-all": "mocha -t 60000 --exit 'test/**/**.mjs'"
|
|
17
17
|
},
|
|
18
18
|
"bin": {
|
|
19
19
|
"build-cnpg-image": "src/build-cnpg-image.mjs",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"firebaseServe": "src/firebaseServe.mjs",
|
|
35
35
|
"gcp-snapshots": "src/gcp-snapshots.mjs",
|
|
36
36
|
"generate-docs": "src/generate-docs.mjs",
|
|
37
|
+
"github-actions-it": "src/github-actions-it.mjs",
|
|
37
38
|
"getfbcfg": "src/getfbcfg.mjs",
|
|
38
39
|
"getjson": "src/getjson.mjs",
|
|
39
40
|
"git-tar": "src/git-tar.sh",
|
|
@@ -84,7 +85,7 @@
|
|
|
84
85
|
"chalk": "^5.6.2",
|
|
85
86
|
"command-line-args": "^6.0.2",
|
|
86
87
|
"command-line-usage": "^7.0.4",
|
|
87
|
-
"commander": "^
|
|
88
|
+
"commander": "^15.0.0",
|
|
88
89
|
"deepmerge": "^4.3.1",
|
|
89
90
|
"enquirer": "^2.4.1",
|
|
90
91
|
"execa": "^9.6.1",
|
|
@@ -102,7 +103,7 @@
|
|
|
102
103
|
"p-limit": "^7.3.0",
|
|
103
104
|
"package-up": "^5.0.0",
|
|
104
105
|
"readline-sync": "^1.4.10",
|
|
105
|
-
"semver": "
|
|
106
|
+
"semver": "7.8.4",
|
|
106
107
|
"shell-quote": "^1.8.4",
|
|
107
108
|
"simple-git": "^3.36.0",
|
|
108
109
|
"sloc": "^0.3.2",
|
|
@@ -117,6 +118,6 @@
|
|
|
117
118
|
"chai": "^6.2.2",
|
|
118
119
|
"eslint": "^9",
|
|
119
120
|
"mocha": "^11.7.6",
|
|
120
|
-
"npm": "^11.
|
|
121
|
+
"npm": "^11.17.0"
|
|
121
122
|
}
|
|
122
123
|
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable security/detect-non-literal-fs-filename */
|
|
3
|
+
import fs from 'node:fs'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
|
|
6
|
+
import { program } from 'commander'
|
|
7
|
+
import chalk from 'chalk'
|
|
8
|
+
import YAML from 'js-yaml'
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
enableDebug,
|
|
12
|
+
errorExit,
|
|
13
|
+
getGitRootDirectory,
|
|
14
|
+
getIsYarnProject,
|
|
15
|
+
log,
|
|
16
|
+
mkdirSafe,
|
|
17
|
+
proceed,
|
|
18
|
+
} from './Utils.mjs'
|
|
19
|
+
|
|
20
|
+
const GH_ACTIONS_REF = 'development'
|
|
21
|
+
const CIRCLE_YML = '.circleci/config.yml'
|
|
22
|
+
const GH_WORKFLOWS_DIR = '.github/workflows'
|
|
23
|
+
const GH_CI_YML = `${GH_WORKFLOWS_DIR}/ci.yml`
|
|
24
|
+
const DEFAULT_COVERAGE_THRESHOLD = 70
|
|
25
|
+
const DEFAULT_CACHE_CONFIG = '{"type":"inMemory"}'
|
|
26
|
+
|
|
27
|
+
program
|
|
28
|
+
.name( 'github-actions-it' )
|
|
29
|
+
.description( chalk.green( 'Installs or updates GitHub Actions CI configuration for a Leverege library repository' ) )
|
|
30
|
+
.option( '--debug', 'Enable debug logging' )
|
|
31
|
+
.option( '--dry-run', 'Show what would be written without making changes' )
|
|
32
|
+
.addHelpText( 'after', `
|
|
33
|
+
${chalk.yellow( 'Files managed:' )}
|
|
34
|
+
${chalk.green( GH_CI_YML )} GitHub Actions CI workflow
|
|
35
|
+
|
|
36
|
+
${chalk.yellow( 'Notes:' )}
|
|
37
|
+
Run from anywhere inside a git repository.
|
|
38
|
+
Reads .circleci/config.yml to preserve existing settings when present.
|
|
39
|
+
Redis is always available on port 6379 — no configuration needed.
|
|
40
|
+
Yarn auth and nodeLinker are handled by the workflow writing ~/.yarnrc.yml on the runner.
|
|
41
|
+
|
|
42
|
+
${chalk.yellow( 'Examples:' )}
|
|
43
|
+
${chalk.green( 'github-actions-it' )} install or upgrade
|
|
44
|
+
${chalk.green( 'github-actions-it --dry-run' )} preview without writing files
|
|
45
|
+
` )
|
|
46
|
+
.parse()
|
|
47
|
+
|
|
48
|
+
const options = program.opts()
|
|
49
|
+
if ( options.debug ) { enableDebug() }
|
|
50
|
+
|
|
51
|
+
const gitRoot = await getGitRootDirectory()
|
|
52
|
+
if ( !gitRoot ) {
|
|
53
|
+
errorExit( 'This command must be run inside a git repository' )
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ---------- Parse existing CircleCI config ----------
|
|
57
|
+
|
|
58
|
+
const circleYmlPath = path.join( gitRoot, CIRCLE_YML )
|
|
59
|
+
|
|
60
|
+
let enableGcp = false
|
|
61
|
+
let coverageThreshold = DEFAULT_COVERAGE_THRESHOLD
|
|
62
|
+
let cacheConfig = DEFAULT_CACHE_CONFIG
|
|
63
|
+
let redisEnabled = false
|
|
64
|
+
let isYarnFromCircle = false
|
|
65
|
+
|
|
66
|
+
if ( fs.existsSync( circleYmlPath ) ) {
|
|
67
|
+
const circleConfig = YAML.load( fs.readFileSync( circleYmlPath, 'utf8' ) )
|
|
68
|
+
|
|
69
|
+
const allJobs = []
|
|
70
|
+
for ( const workflow of Object.values( circleConfig.workflows ?? {} ) ) {
|
|
71
|
+
for ( const job of ( workflow.jobs ?? [] ) ) {
|
|
72
|
+
if ( typeof job === 'object' ) {
|
|
73
|
+
for ( const [ name, config ] of Object.entries( job ) ) {
|
|
74
|
+
allJobs.push( { name, config: config ?? {} } )
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const coverageJob = allJobs.find( j => j.name === 'leverege/code-coverage' )
|
|
81
|
+
if ( coverageJob ) {
|
|
82
|
+
const { config } = coverageJob
|
|
83
|
+
coverageThreshold = config['coverage-threshold'] ?? DEFAULT_COVERAGE_THRESHOLD
|
|
84
|
+
cacheConfig = config['cache-config'] ?? DEFAULT_CACHE_CONFIG
|
|
85
|
+
redisEnabled = config['enable-redis'] === true
|
|
86
|
+
|
|
87
|
+
const ctx = config.context
|
|
88
|
+
const contexts = Array.isArray( ctx ) ? ctx : ( ctx ? [ ctx ] : [] )
|
|
89
|
+
enableGcp = contexts.includes( 'leverege-gcp' )
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
isYarnFromCircle = allJobs.some( j => j.config['pkg-manager'] === 'yarn-berry' )
|
|
93
|
+
|
|
94
|
+
log( chalk.blue( '\nParsed CircleCI config:' ) )
|
|
95
|
+
log( ` pkg-manager: ${isYarnFromCircle ? 'yarn-berry' : 'npm'}` )
|
|
96
|
+
log( ` enable-gcp: ${enableGcp}` )
|
|
97
|
+
log( ` coverage-threshold: ${coverageThreshold}` )
|
|
98
|
+
log( ` cache-config: ${cacheConfig}` )
|
|
99
|
+
log( ` enable-redis: ${redisEnabled}` )
|
|
100
|
+
} else {
|
|
101
|
+
log( chalk.yellow( '\nNo .circleci/config.yml found — using defaults' ) )
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const isYarn = isYarnFromCircle || getIsYarnProject( gitRoot )
|
|
105
|
+
log( chalk.blue( `\nPackage manager: ${isYarn ? 'yarn-berry' : 'npm'}` ) )
|
|
106
|
+
|
|
107
|
+
if ( redisEnabled ) {
|
|
108
|
+
log( chalk.yellow( '\nRedis detected — Redis service is always available on port 6379 in GitHub Actions' ) )
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ---------- Determine what needs writing ----------
|
|
112
|
+
|
|
113
|
+
const ciYmlPath = path.join( gitRoot, GH_CI_YML )
|
|
114
|
+
let ciYmlExists = false
|
|
115
|
+
|
|
116
|
+
if ( fs.existsSync( ciYmlPath ) ) {
|
|
117
|
+
ciYmlExists = true
|
|
118
|
+
const existingCi = fs.readFileSync( ciYmlPath, 'utf8' )
|
|
119
|
+
if ( existingCi.includes( `library-ci.yml@${GH_ACTIONS_REF}` ) ) {
|
|
120
|
+
log( chalk.yellow( '\nExisting GitHub Actions CI config found — will update' ) )
|
|
121
|
+
} else {
|
|
122
|
+
log( chalk.yellow( '\nExisting .github/workflows/ci.yml found (not managed by github-actions-it) — will overwrite' ) )
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ---------- Generate content ----------
|
|
127
|
+
|
|
128
|
+
function generateCiYml() {
|
|
129
|
+
const withLines = []
|
|
130
|
+
if ( enableGcp ) {
|
|
131
|
+
withLines.push( ' enable-gcp: true' )
|
|
132
|
+
withLines.push( ' gcp-project: leverege-registry' )
|
|
133
|
+
}
|
|
134
|
+
if ( coverageThreshold !== DEFAULT_COVERAGE_THRESHOLD ) {
|
|
135
|
+
withLines.push( ` coverage-threshold: ${coverageThreshold}` )
|
|
136
|
+
}
|
|
137
|
+
if ( cacheConfig !== DEFAULT_CACHE_CONFIG ) {
|
|
138
|
+
withLines.push( ` cache-config: '${cacheConfig}'` )
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const lines = [
|
|
142
|
+
'name: CI',
|
|
143
|
+
'',
|
|
144
|
+
'on:',
|
|
145
|
+
' push:',
|
|
146
|
+
' pull_request:',
|
|
147
|
+
' workflow_dispatch:',
|
|
148
|
+
'',
|
|
149
|
+
'jobs:',
|
|
150
|
+
' ci:',
|
|
151
|
+
' permissions:',
|
|
152
|
+
' id-token: write',
|
|
153
|
+
' contents: read',
|
|
154
|
+
` uses: Leverege/github-actions/.github/workflows/library-ci.yml@${GH_ACTIONS_REF}`,
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
if ( withLines.length > 0 ) {
|
|
158
|
+
lines.push( ' with:' )
|
|
159
|
+
lines.push( ...withLines )
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
lines.push( ' secrets: inherit', '' )
|
|
163
|
+
return lines.join( '\n' )
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ---------- Dry run ----------
|
|
167
|
+
|
|
168
|
+
if ( options.dryRun ) {
|
|
169
|
+
log( chalk.green( `\n[dry-run] Would write ${GH_CI_YML}:\n` ) )
|
|
170
|
+
log( generateCiYml() )
|
|
171
|
+
process.exit( 0 )
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ---------- Confirm overwrites ----------
|
|
175
|
+
|
|
176
|
+
if ( ciYmlExists ) {
|
|
177
|
+
await proceed( `Overwrite ${GH_CI_YML}?` )
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ---------- Write ----------
|
|
181
|
+
|
|
182
|
+
mkdirSafe( path.join( gitRoot, GH_WORKFLOWS_DIR ) )
|
|
183
|
+
fs.writeFileSync( ciYmlPath, generateCiYml() )
|
|
184
|
+
log( chalk.green( `\nGitHub Actions CI config written => ${GH_CI_YML}` ) )
|
|
185
|
+
|
|
186
|
+
log( chalk.yellow( '\nNext steps:' ) )
|
|
187
|
+
log( ` git add ${GH_CI_YML} && git commit -m "CHORE add GitHub Actions CI"\n` )
|
|
@@ -70,12 +70,13 @@ prometheus:
|
|
|
70
70
|
ruleSelectorNilUsesHelmValues: false
|
|
71
71
|
serviceMonitorSelectorNilUsesHelmValues: false
|
|
72
72
|
probeSelectorNilUsesHelmValues: false
|
|
73
|
-
maximumStartupDurationSeconds:
|
|
73
|
+
maximumStartupDurationSeconds: 300
|
|
74
74
|
resources:
|
|
75
75
|
requests:
|
|
76
76
|
cpu: 500m
|
|
77
77
|
memory: 2Gi
|
|
78
78
|
retention: 30d
|
|
79
|
+
retentionSize: 48GiB
|
|
79
80
|
storageSpec:
|
|
80
81
|
volumeClaimTemplate:
|
|
81
82
|
spec:
|
package/src/repo-panopticon.mjs
CHANGED
|
@@ -32,7 +32,9 @@ const CHECKS = [
|
|
|
32
32
|
const match = content.match( /leverege\/circle-nodejs-ci@(\d+)\.\d+\.\d+/ )
|
|
33
33
|
if ( !match || parseInt( match[1], 10 ) === 0 ) return { value : chalk.hex( '#FFA500' )( 'L' ) }
|
|
34
34
|
const major = parseInt( match[1], 10 )
|
|
35
|
-
|
|
35
|
+
if ( major === 1 ) return { value : chalk.yellow( '1' ) }
|
|
36
|
+
const hasGHA = fs.existsSync( path.join( dir, '.github', 'workflows', 'ci.yml' ) )
|
|
37
|
+
return { value : hasGHA ? chalk.green( '★' ) : chalk.green( `${major}` ) }
|
|
36
38
|
} catch {
|
|
37
39
|
return { value : chalk.hex( '#FFA500' )( 'L' ) }
|
|
38
40
|
}
|
|
@@ -327,7 +329,7 @@ ${chalk.yellow( 'Columns:' )}
|
|
|
327
329
|
${chalk.green( 'git' )} latest semver git tag (green=match, yellow=mismatch, red=untagged)
|
|
328
330
|
${chalk.green( 'name' )} orange if dirty: pull/fetch failed (regular repos) or local modifications present (workspace packages)
|
|
329
331
|
${chalk.green( 'scope' )} package scope: @org, PRVT, or PUBL
|
|
330
|
-
${chalk.green( 'cir' )}
|
|
332
|
+
${chalk.green( 'cir' )} CI status: ✘=missing, L=legacy, 1=orb v1, 2=orb v2, ★=orb v2 + GHA ci.yml
|
|
331
333
|
${chalk.green( 'ESM' )} "type": "module" in package.json
|
|
332
334
|
${chalk.green( 'har' )} .har directory present at repo root
|
|
333
335
|
${chalk.green( 'lnt' )} ESLint version from node_modules (✘=no lint script, ?=not installed, yellow=v8, green=v9+)
|