pipecraft 0.29.3 → 0.36.2
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 +98 -34
- package/dist/cli/index.d.ts +3 -3
- package/dist/cli/index.js +66 -24
- package/dist/cli/index.js.map +1 -1
- package/dist/generators/init.tpl.d.ts +4 -4
- package/dist/generators/init.tpl.d.ts.map +1 -1
- package/dist/generators/init.tpl.js +310 -83
- package/dist/generators/init.tpl.js.map +1 -1
- package/dist/generators/workflows.tpl.d.ts +9 -9
- package/dist/generators/workflows.tpl.d.ts.map +1 -1
- package/dist/generators/workflows.tpl.js +33 -24
- package/dist/generators/workflows.tpl.js.map +1 -1
- package/dist/templates/actions/calculate-version.yml.tpl.d.ts +7 -4
- package/dist/templates/actions/calculate-version.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/calculate-version.yml.tpl.js +16 -9
- package/dist/templates/actions/calculate-version.yml.tpl.js.map +1 -1
- package/dist/templates/actions/create-pr.yml.tpl.d.ts +5 -2
- package/dist/templates/actions/create-pr.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/create-pr.yml.tpl.js +9 -6
- package/dist/templates/actions/create-pr.yml.tpl.js.map +1 -1
- package/dist/templates/actions/create-release.yml.tpl.d.ts +5 -2
- package/dist/templates/actions/create-release.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/create-release.yml.tpl.js +9 -6
- package/dist/templates/actions/create-release.yml.tpl.js.map +1 -1
- package/dist/templates/actions/create-tag.yml.tpl.d.ts +5 -2
- package/dist/templates/actions/create-tag.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/create-tag.yml.tpl.js +9 -6
- package/dist/templates/actions/create-tag.yml.tpl.js.map +1 -1
- package/dist/templates/actions/detect-changes.yml.tpl.d.ts +24 -52
- package/dist/templates/actions/detect-changes.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/detect-changes.yml.tpl.js +281 -108
- package/dist/templates/actions/detect-changes.yml.tpl.js.map +1 -1
- package/dist/templates/actions/manage-branch.yml.tpl.d.ts +5 -2
- package/dist/templates/actions/manage-branch.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/manage-branch.yml.tpl.js +9 -6
- package/dist/templates/actions/manage-branch.yml.tpl.js.map +1 -1
- package/dist/templates/actions/promote-branch.yml.tpl.d.ts +5 -2
- package/dist/templates/actions/promote-branch.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/promote-branch.yml.tpl.js +27 -76
- package/dist/templates/actions/promote-branch.yml.tpl.js.map +1 -1
- package/dist/templates/actions/run-nx-affected.yml.tpl.d.ts +33 -0
- package/dist/templates/actions/run-nx-affected.yml.tpl.d.ts.map +1 -0
- package/dist/templates/actions/run-nx-affected.yml.tpl.js +346 -0
- package/dist/templates/actions/run-nx-affected.yml.tpl.js.map +1 -0
- package/dist/templates/release-it.cjs.tpl.d.ts +1 -1
- package/dist/templates/release-it.cjs.tpl.d.ts.map +1 -1
- package/dist/templates/release-it.cjs.tpl.js +24 -26
- package/dist/templates/release-it.cjs.tpl.js.map +1 -1
- package/dist/templates/workflows/enforce-pr-target.yml.tpl.d.ts +1 -1
- package/dist/templates/workflows/enforce-pr-target.yml.tpl.d.ts.map +1 -1
- package/dist/templates/workflows/enforce-pr-target.yml.tpl.js +2 -3
- package/dist/templates/workflows/enforce-pr-target.yml.tpl.js.map +1 -1
- package/dist/templates/workflows/pipeline-nx.yml.tpl.d.ts +2 -2
- package/dist/templates/workflows/pipeline-nx.yml.tpl.d.ts.map +1 -1
- package/dist/templates/workflows/pipeline-nx.yml.tpl.js +300 -93
- package/dist/templates/workflows/pipeline-nx.yml.tpl.js.map +1 -1
- package/dist/templates/workflows/pipeline.yml.tpl.d.ts +2 -2
- package/dist/templates/workflows/pipeline.yml.tpl.d.ts.map +1 -1
- package/dist/templates/workflows/pipeline.yml.tpl.js +347 -74
- package/dist/templates/workflows/pipeline.yml.tpl.js.map +1 -1
- package/dist/templates/workflows/pr-title-check.yml.tpl.d.ts +1 -1
- package/dist/templates/workflows/pr-title-check.yml.tpl.d.ts.map +1 -1
- package/dist/templates/workflows/pr-title-check.yml.tpl.js +101 -22
- package/dist/templates/workflows/pr-title-check.yml.tpl.js.map +1 -1
- package/dist/templates/workflows/shared/index.d.ts +3 -2
- package/dist/templates/workflows/shared/index.d.ts.map +1 -1
- package/dist/templates/workflows/shared/index.js +3 -2
- package/dist/templates/workflows/shared/index.js.map +1 -1
- package/dist/templates/workflows/shared/operations-changes.d.ts +13 -2
- package/dist/templates/workflows/shared/operations-changes.d.ts.map +1 -1
- package/dist/templates/workflows/shared/operations-changes.js +47 -16
- package/dist/templates/workflows/shared/operations-changes.js.map +1 -1
- package/dist/templates/workflows/shared/operations-domain-jobs.d.ts +18 -1
- package/dist/templates/workflows/shared/operations-domain-jobs.d.ts.map +1 -1
- package/dist/templates/workflows/shared/operations-domain-jobs.js +142 -17
- package/dist/templates/workflows/shared/operations-domain-jobs.js.map +1 -1
- package/dist/templates/workflows/shared/operations-gate.d.ts +32 -0
- package/dist/templates/workflows/shared/operations-gate.d.ts.map +1 -0
- package/dist/templates/workflows/shared/operations-gate.js +77 -0
- package/dist/templates/workflows/shared/operations-gate.js.map +1 -0
- package/dist/templates/workflows/shared/operations-header.d.ts +1 -1
- package/dist/templates/workflows/shared/operations-header.d.ts.map +1 -1
- package/dist/templates/workflows/shared/operations-header.js +46 -6
- package/dist/templates/workflows/shared/operations-header.js.map +1 -1
- package/dist/templates/workflows/shared/operations-tag-promote.d.ts +5 -1
- package/dist/templates/workflows/shared/operations-tag-promote.d.ts.map +1 -1
- package/dist/templates/workflows/shared/operations-tag-promote.js +138 -31
- package/dist/templates/workflows/shared/operations-tag-promote.js.map +1 -1
- package/dist/templates/workflows/shared/operations-version.d.ts +3 -1
- package/dist/templates/workflows/shared/operations-version.d.ts.map +1 -1
- package/dist/templates/workflows/shared/operations-version.js +18 -10
- package/dist/templates/workflows/shared/operations-version.js.map +1 -1
- package/dist/templates/yaml-format-utils.d.ts.map +1 -1
- package/dist/templates/yaml-format-utils.js.map +1 -1
- package/dist/types/index.d.ts +57 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/action-reference.d.ts +73 -0
- package/dist/utils/action-reference.d.ts.map +1 -0
- package/dist/utils/action-reference.js +120 -0
- package/dist/utils/action-reference.js.map +1 -0
- package/dist/utils/ast-path-operations.d.ts +3 -3
- package/dist/utils/ast-path-operations.d.ts.map +1 -1
- package/dist/utils/ast-path-operations.js +58 -17
- package/dist/utils/ast-path-operations.js.map +1 -1
- package/dist/utils/config.d.ts +11 -5
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +33 -8
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/github-setup.d.ts +4 -4
- package/dist/utils/github-setup.d.ts.map +1 -1
- package/dist/utils/github-setup.js +57 -36
- package/dist/utils/github-setup.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/messaging.d.ts.map +1 -1
- package/dist/utils/messaging.js +7 -3
- package/dist/utils/messaging.js.map +1 -1
- package/dist/utils/preflight.d.ts +2 -2
- package/dist/utils/preflight.d.ts.map +1 -1
- package/dist/utils/preflight.js +43 -41
- package/dist/utils/preflight.js.map +1 -1
- package/dist/utils/versioning.d.ts +1 -1
- package/dist/utils/versioning.d.ts.map +1 -1
- package/dist/utils/versioning.js +10 -10
- package/dist/utils/versioning.js.map +1 -1
- package/package.json +11 -4
- package/src/generators/init.tpl.ts +374 -102
- package/src/generators/workflows.tpl.ts +54 -45
- package/dist/templates/actions/detect-changes-nx.yml.tpl.d.ts +0 -32
- package/dist/templates/actions/detect-changes-nx.yml.tpl.d.ts.map +0 -1
- package/dist/templates/actions/detect-changes-nx.yml.tpl.js +0 -227
- package/dist/templates/actions/detect-changes-nx.yml.tpl.js.map +0 -1
- package/dist/utils/idempotency.d.ts +0 -187
- package/dist/utils/idempotency.d.ts.map +0 -1
- package/dist/utils/idempotency.js +0 -304
- package/dist/utils/idempotency.js.map +0 -1
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* @module templates/release-it.cjs.tpl
|
|
14
14
|
*/
|
|
15
|
-
import {
|
|
15
|
+
import { renderTemplate, toFile } from '@featherscloud/pinion';
|
|
16
16
|
import { logger } from '../utils/logger.js';
|
|
17
17
|
/**
|
|
18
18
|
* Generate release-it configuration content
|
|
@@ -26,32 +26,30 @@ import { logger } from '../utils/logger.js';
|
|
|
26
26
|
* @returns {string} JavaScript configuration content
|
|
27
27
|
*/
|
|
28
28
|
const releaseItTemplate = (ctx) => {
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
// Base default prefixes for conventional commits
|
|
30
|
+
const baseDefaults = {
|
|
31
|
+
test: 'ignore',
|
|
32
|
+
build: 'ignore',
|
|
33
|
+
ci: 'patch',
|
|
34
|
+
docs: 'patch',
|
|
35
|
+
chore: 'minor',
|
|
36
|
+
style: 'patch',
|
|
31
37
|
fix: 'patch',
|
|
32
|
-
|
|
38
|
+
perf: 'patch',
|
|
39
|
+
refactor: 'patch',
|
|
40
|
+
feat: 'minor',
|
|
41
|
+
major: 'major'
|
|
33
42
|
};
|
|
34
|
-
//
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
// Get user-defined bump rules from config
|
|
44
|
+
const userBumpRules = ctx.config?.semver?.bumpRules || ctx.semver?.bumpRules || {};
|
|
45
|
+
// Merge user rules with defaults (user rules take precedence)
|
|
46
|
+
const mergedRules = { ...baseDefaults, ...userBumpRules };
|
|
47
|
+
// Convert to formatted string for the config file
|
|
48
|
+
const rulesEntries = Object.entries(mergedRules)
|
|
49
|
+
.map(([type, level]) => ` ${type}: '${level}'`)
|
|
50
|
+
.join(',\n');
|
|
41
51
|
return `const DEFAULT_PREFIXES = {
|
|
42
|
-
|
|
43
|
-
build: 'ignore',
|
|
44
|
-
|
|
45
|
-
ci: 'patch',
|
|
46
|
-
docs: 'patch',
|
|
47
|
-
chore: 'minor',
|
|
48
|
-
style: 'patch',
|
|
49
|
-
fix: 'patch',
|
|
50
|
-
perf: 'patch',
|
|
51
|
-
refactor: 'patch',
|
|
52
|
-
|
|
53
|
-
feat: 'minor',
|
|
54
|
-
major: 'major',
|
|
52
|
+
${rulesEntries}
|
|
55
53
|
}
|
|
56
54
|
|
|
57
55
|
module.exports = {
|
|
@@ -137,12 +135,12 @@ module.exports = {
|
|
|
137
135
|
* ```
|
|
138
136
|
*/
|
|
139
137
|
export const generate = (ctx) => Promise.resolve(ctx)
|
|
140
|
-
.then(
|
|
138
|
+
.then(ctx => {
|
|
141
139
|
logger.verbose('📝 Generating release-it configuration...');
|
|
142
140
|
return ctx;
|
|
143
141
|
})
|
|
144
142
|
.then(renderTemplate((ctx) => releaseItTemplate(ctx), toFile('.release-it.cjs')))
|
|
145
|
-
.then(
|
|
143
|
+
.then(ctx => {
|
|
146
144
|
logger.verbose('✅ Generated .release-it.cjs');
|
|
147
145
|
return ctx;
|
|
148
146
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release-it.cjs.tpl.js","sourceRoot":"","sources":["../../src/templates/release-it.cjs.tpl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"release-it.cjs.tpl.js","sourceRoot":"","sources":["../../src/templates/release-it.cjs.tpl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAsB,cAAc,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAClF,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAE3C;;;;;;;;;;GAUG;AACH,MAAM,iBAAiB,GAAG,CAAC,GAAQ,EAAE,EAAE;IACrC,iDAAiD;IACjD,MAAM,YAAY,GAA2B;QAC3C,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,QAAQ;QACf,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,OAAO;QACd,GAAG,EAAE,OAAO;QACZ,IAAI,EAAE,OAAO;QACb,QAAQ,EAAE,OAAO;QACjB,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;KACf,CAAA;IAED,0CAA0C;IAC1C,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,CAAA;IAElF,8DAA8D;IAC9D,MAAM,WAAW,GAAG,EAAE,GAAG,YAAY,EAAE,GAAG,aAAa,EAAE,CAAA;IAEzD,kDAAkD;IAClD,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;SAC7C,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,MAAM,KAAK,GAAG,CAAC;SAC/C,IAAI,CAAC,KAAK,CAAC,CAAA;IAEd,OAAO;EACP,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2DV,CAAA;AACJ,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,GAAkB,EAAE,EAAE,CAC7C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;KACjB,IAAI,CAAC,GAAG,CAAC,EAAE;IACV,MAAM,CAAC,OAAO,CAAC,2CAA2C,CAAC,CAAA;IAC3D,OAAO,GAAG,CAAA;AACZ,CAAC,CAAC;KACD,IAAI,CAAC,cAAc,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;KACrF,IAAI,CAAC,GAAG,CAAC,EAAE;IACV,MAAM,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAA;IAC7C,OAAO,GAAG,CAAA;AACZ,CAAC,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enforce-pr-target.yml.tpl.d.ts","sourceRoot":"","sources":["../../../src/templates/workflows/enforce-pr-target.yml.tpl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,aAAa,EAA0B,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"enforce-pr-target.yml.tpl.d.ts","sourceRoot":"","sources":["../../../src/templates/workflows/enforce-pr-target.yml.tpl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,KAAK,aAAa,EAA0B,MAAM,uBAAuB,CAAA;AAElF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,QAAQ,GAAI,KAAK,aAAa,iBAiCxC,CAAA"}
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* })
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
|
-
import {
|
|
29
|
+
import { renderTemplate, toFile } from '@featherscloud/pinion';
|
|
30
30
|
/**
|
|
31
31
|
* Generates the enforce-pr-target.yml workflow file.
|
|
32
32
|
*
|
|
@@ -49,8 +49,7 @@ import { toFile, renderTemplate } from '@featherscloud/pinion';
|
|
|
49
49
|
* // Creates: .github/workflows/enforce-pr-target.yml
|
|
50
50
|
* ```
|
|
51
51
|
*/
|
|
52
|
-
export const generate = (ctx) => Promise.resolve(ctx)
|
|
53
|
-
.then(renderTemplate((ctx) => {
|
|
52
|
+
export const generate = (ctx) => Promise.resolve(ctx).then(renderTemplate((ctx) => {
|
|
54
53
|
const { initialBranch = 'develop', finalBranch = 'main' } = ctx;
|
|
55
54
|
return `name: Enforce PR Target Branch
|
|
56
55
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enforce-pr-target.yml.tpl.js","sourceRoot":"","sources":["../../../src/templates/workflows/enforce-pr-target.yml.tpl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"enforce-pr-target.yml.tpl.js","sourceRoot":"","sources":["../../../src/templates/workflows/enforce-pr-target.yml.tpl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAsB,cAAc,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAElF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,GAAkB,EAAE,EAAE,CAC7C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CACvB,cAAc,CAAC,CAAC,GAAQ,EAAE,EAAE;IAC1B,MAAM,EAAE,aAAa,GAAG,SAAS,EAAE,WAAW,GAAG,MAAM,EAAE,GAAG,GAAG,CAAA;IAE/D,OAAO;;;;;;;;;;;kCAWqB,WAAW;;sDAES,aAAa,kBAAkB,WAAW;6DACnC,aAAa;;;;;8CAK5B,WAAW,SAAS,aAAa;;;;kCAI7C,aAAa;;0CAEL,aAAa;CACtD,CAAA;AACG,CAAC,EAAE,MAAM,CAAC,yCAAyC,CAAC,CAAC,CACtD,CAAA"}
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
* This is Option 1 (Sequential Strategy) - simple, fast, and leverages Nx's intelligence.
|
|
9
9
|
*/
|
|
10
|
-
import { PinionContext } from '@featherscloud/pinion';
|
|
11
|
-
import { PipecraftConfig } from '../../types/index.js';
|
|
10
|
+
import { type PinionContext } from '@featherscloud/pinion';
|
|
11
|
+
import type { PipecraftConfig } from '../../types/index.js';
|
|
12
12
|
interface NxPipelineContext extends PinionContext {
|
|
13
13
|
config: PipecraftConfig;
|
|
14
14
|
branchFlow: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-nx.yml.tpl.d.ts","sourceRoot":"","sources":["../../../src/templates/workflows/pipeline-nx.yml.tpl.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAA0B,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"pipeline-nx.yml.tpl.d.ts","sourceRoot":"","sources":["../../../src/templates/workflows/pipeline-nx.yml.tpl.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,aAAa,EAA0B,MAAM,uBAAuB,CAAA;AAGlF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAoB3D,UAAU,iBAAkB,SAAQ,aAAa;IAC/C,MAAM,EAAE,eAAe,CAAA;IACvB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAgHD;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,KAAK,iBAAiB,iBA2U1C,CAAA"}
|
|
@@ -8,86 +8,102 @@
|
|
|
8
8
|
* This is Option 1 (Sequential Strategy) - simple, fast, and leverages Nx's intelligence.
|
|
9
9
|
*/
|
|
10
10
|
import { renderTemplate, toFile } from '@featherscloud/pinion';
|
|
11
|
-
import { parseDocument, stringify } from 'yaml';
|
|
12
11
|
import fs from 'fs';
|
|
13
|
-
import {
|
|
12
|
+
import { parseDocument, Scalar, stringify } from 'yaml';
|
|
14
13
|
import { applyPathOperations, createValueFromString } from '../../utils/ast-path-operations.js';
|
|
15
|
-
import {
|
|
14
|
+
import { logger } from '../../utils/logger.js';
|
|
16
15
|
import { formatIfConditions } from '../yaml-format-utils.js';
|
|
16
|
+
import { createChangesJobOperation, createGateJobOperation, createHeaderOperations, createTagPromoteReleaseOperations, createVersionJobOperation, getDomainJobNames } from './shared/index.js';
|
|
17
|
+
/**
|
|
18
|
+
* Extract user-customized section between markers from YAML content
|
|
19
|
+
* Returns content WITHOUT the markers themselves
|
|
20
|
+
* Uses unique delimiters as YAML comments (indentation-independent)
|
|
21
|
+
*/
|
|
22
|
+
function extractUserSection(yamlContent) {
|
|
23
|
+
// Match markers as YAML comments: any leading whitespace + one or more # + optional whitespace + marker
|
|
24
|
+
// Example: " ### <--START CUSTOM JOBS-->"
|
|
25
|
+
const startMarkerRegex = /^.*#+\s*<--START CUSTOM JOBS-->\s*$/m;
|
|
26
|
+
const endMarkerRegex = /^.*#+\s*<--END CUSTOM JOBS-->\s*$/m;
|
|
27
|
+
const startMatch = yamlContent.match(startMarkerRegex);
|
|
28
|
+
const endMatch = yamlContent.match(endMarkerRegex);
|
|
29
|
+
if (!startMatch || !endMatch) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const startIndex = startMatch.index + startMatch[0].length;
|
|
33
|
+
const endIndex = endMatch.index;
|
|
34
|
+
// Extract content between markers (NOT including the markers themselves)
|
|
35
|
+
let extracted = yamlContent.substring(startIndex, endIndex);
|
|
36
|
+
// Normalize whitespace: remove leading/trailing newlines
|
|
37
|
+
// These will be added back consistently during insertion
|
|
38
|
+
extracted = extracted.replace(/^\n+/, '');
|
|
39
|
+
extracted = extracted.replace(/\n+$/, '');
|
|
40
|
+
return extracted;
|
|
41
|
+
}
|
|
17
42
|
/**
|
|
18
|
-
* Create the nx
|
|
43
|
+
* Create the test-nx job operation (Nx-specific)
|
|
19
44
|
*/
|
|
20
|
-
function
|
|
45
|
+
function createTestNxJobOperation(ctx) {
|
|
21
46
|
const { config } = ctx;
|
|
22
47
|
const nxConfig = config.nx;
|
|
23
48
|
const packageManager = config.packageManager || 'npm';
|
|
24
49
|
const enableCache = nxConfig.enableCache !== false;
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
run: npx nx affected --target=${task} --base=\${{ inputs.baseRef || '${nxConfig.baseRef || 'origin/main'}' }}`)
|
|
28
|
-
.join('\n');
|
|
50
|
+
const targets = nxConfig.tasks.join(',');
|
|
51
|
+
// Build the job steps
|
|
29
52
|
const cacheStep = enableCache
|
|
30
53
|
? `
|
|
31
54
|
- name: Cache Nx
|
|
32
55
|
uses: actions/cache@v4
|
|
33
56
|
with:
|
|
34
57
|
path: .nx/cache
|
|
35
|
-
|
|
36
|
-
# Nx cache accumulates computation results, so we want to save after every run
|
|
37
|
-
# restore-keys ensure we start from the most recent cache on this branch
|
|
38
|
-
key: nx-\${{ runner.os }}-\${{ hashFiles('package-lock.json') }}-\${{ github.ref_name }}-\${{ github.run_number }}
|
|
58
|
+
key: \${{ runner.os }}-nx-\${{ hashFiles('**/nx.json', '**/.nxignore', '**/package-lock.json', '**/pnpm-lock.yaml', '**/yarn.lock') }}
|
|
39
59
|
restore-keys: |
|
|
40
|
-
|
|
41
|
-
nx-\${{ runner.os }}-\${{ hashFiles('package-lock.json') }}-
|
|
42
|
-
nx-\${{ runner.os }}-
|
|
43
|
-
`
|
|
60
|
+
\${{ runner.os }}-nx-`
|
|
44
61
|
: '';
|
|
62
|
+
// Build individual task steps
|
|
63
|
+
const taskSteps = nxConfig.tasks
|
|
64
|
+
.map(target => `
|
|
65
|
+
- name: Run nx affected --target=${target}
|
|
66
|
+
run: |
|
|
67
|
+
npx nx affected --target=${target} --base=\${{ inputs.baseRef || '${nxConfig.baseRef || 'origin/main'}' }} || echo "No affected projects"`)
|
|
68
|
+
.join('');
|
|
45
69
|
return {
|
|
46
|
-
path: 'jobs.nx
|
|
47
|
-
operation: '
|
|
70
|
+
path: 'jobs.test-nx',
|
|
71
|
+
operation: 'preserve', // User can customize this job!
|
|
48
72
|
commentBefore: `
|
|
49
73
|
=============================================================================
|
|
50
|
-
|
|
74
|
+
TEST-NX ( ✅ Customize these with your test logic)
|
|
51
75
|
=============================================================================
|
|
52
|
-
This job runs all Nx tasks sequentially using \`nx affected\`.
|
|
53
|
-
Nx handles dependency detection, caching, and parallel execution internally.
|
|
76
|
+
This job runs all Nx tasks sequentially using \`nx affected\`.
|
|
77
|
+
Nx handles dependency detection, caching, and parallel execution internally.
|
|
54
78
|
`,
|
|
55
79
|
value: createValueFromString(`
|
|
56
|
-
needs: changes
|
|
80
|
+
needs: [ changes ]
|
|
57
81
|
runs-on: ubuntu-latest
|
|
58
82
|
steps:
|
|
59
|
-
-
|
|
60
|
-
uses: actions/checkout@v4
|
|
83
|
+
- uses: actions/checkout@v4
|
|
61
84
|
with:
|
|
62
85
|
ref: \${{ inputs.commitSha || github.sha }}
|
|
63
|
-
fetch-depth:
|
|
64
|
-
|
|
86
|
+
fetch-depth: \${{ env.FETCH_DEPTH_AFFECTED }}
|
|
65
87
|
- name: Setup Node.js
|
|
66
88
|
uses: actions/setup-node@v4
|
|
67
89
|
with:
|
|
68
|
-
node-version:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
yarn
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
;;
|
|
86
|
-
esac
|
|
87
|
-
env:
|
|
88
|
-
packageManager: ${packageManager}
|
|
89
|
-
${cacheStep}
|
|
90
|
-
${taskSteps}
|
|
90
|
+
node-version: \${{ env.NODE_VERSION }}
|
|
91
|
+
${packageManager === 'pnpm'
|
|
92
|
+
? `
|
|
93
|
+
- name: Setup pnpm
|
|
94
|
+
uses: pnpm/action-setup@v4
|
|
95
|
+
with:
|
|
96
|
+
version: \${{ env.PNPM_VERSION }}
|
|
97
|
+
- name: Install dependencies
|
|
98
|
+
run: pnpm install --frozen-lockfile`
|
|
99
|
+
: packageManager === 'yarn'
|
|
100
|
+
? `
|
|
101
|
+
- name: Install dependencies
|
|
102
|
+
run: yarn install --frozen-lockfile`
|
|
103
|
+
: `
|
|
104
|
+
- name: Install dependencies
|
|
105
|
+
run: npm ci`}
|
|
106
|
+
${cacheStep}${taskSteps}
|
|
91
107
|
`)
|
|
92
108
|
};
|
|
93
109
|
}
|
|
@@ -102,7 +118,7 @@ export const generate = (ctx) => Promise.resolve(ctx)
|
|
|
102
118
|
const nxConfig = config.nx;
|
|
103
119
|
// Get domain job names for dependency management
|
|
104
120
|
const { testJobs, deployJobs, remoteTestJobs } = getDomainJobNames(domains);
|
|
105
|
-
// Build operations array
|
|
121
|
+
// Build operations array - only managed jobs
|
|
106
122
|
const operations = [
|
|
107
123
|
// Header (name, run-name, on triggers)
|
|
108
124
|
...createHeaderOperations({ branchFlow }),
|
|
@@ -110,60 +126,202 @@ export const generate = (ctx) => Promise.resolve(ctx)
|
|
|
110
126
|
createChangesJobOperation({
|
|
111
127
|
domains,
|
|
112
128
|
useNx: true,
|
|
113
|
-
baseRef: nxConfig.baseRef || 'origin/main'
|
|
129
|
+
baseRef: nxConfig.baseRef || 'origin/main',
|
|
130
|
+
config
|
|
114
131
|
}),
|
|
115
|
-
// Nx
|
|
116
|
-
|
|
117
|
-
//
|
|
118
|
-
...createDomainTestJobOperations({ domains }),
|
|
119
|
-
// Version calculation
|
|
132
|
+
// Nx test job (runs all Nx tasks)
|
|
133
|
+
createTestNxJobOperation(ctx),
|
|
134
|
+
// Version calculation (depends on test-nx and changes)
|
|
120
135
|
createVersionJobOperation({
|
|
121
|
-
testJobNames:
|
|
122
|
-
nxEnabled: true,
|
|
123
|
-
baseRef: nxConfig.baseRef || 'origin/main'
|
|
136
|
+
testJobNames: [], // No domain test job dependencies
|
|
137
|
+
nxEnabled: true, // Depends on test-nx job
|
|
138
|
+
baseRef: nxConfig.baseRef || 'origin/main',
|
|
139
|
+
config
|
|
140
|
+
}),
|
|
141
|
+
// Gate job (runs after test-nx, gates downstream jobs)
|
|
142
|
+
createGateJobOperation({
|
|
143
|
+
testJobNames: ['test-nx'], // Gate on the Nx test job
|
|
144
|
+
deployJobNames: [] // Could add deploy jobs here if needed
|
|
124
145
|
}),
|
|
125
|
-
// Domain deploy jobs (preserved for user customization)
|
|
126
|
-
...createDomainDeployJobOperations({ domains }),
|
|
127
|
-
// Domain remote test jobs (preserved for user customization)
|
|
128
|
-
...createDomainRemoteTestJobOperations({ domains }),
|
|
129
146
|
// Tag, promote, release
|
|
130
147
|
...createTagPromoteReleaseOperations({
|
|
131
148
|
branchFlow,
|
|
132
|
-
deployJobNames:
|
|
133
|
-
remoteTestJobNames:
|
|
149
|
+
deployJobNames: [], // No deployment dependencies in new model
|
|
150
|
+
remoteTestJobNames: [],
|
|
151
|
+
testJobNames: ['test-nx'], // For Nx, the single test-nx job is the gate
|
|
152
|
+
autoMerge: typeof config.autoMerge === 'object' ? config.autoMerge : {},
|
|
153
|
+
config
|
|
134
154
|
})
|
|
135
155
|
];
|
|
136
156
|
// Check if file exists
|
|
137
|
-
|
|
138
|
-
|
|
157
|
+
const fileExists = fs.existsSync(filePath);
|
|
158
|
+
// Extract user-customized section and custom jobs from existing file if it exists
|
|
159
|
+
let userSection = null;
|
|
160
|
+
const customJobsFromExisting = [];
|
|
161
|
+
if (fileExists) {
|
|
162
|
+
const existingContent = fs.readFileSync(filePath, 'utf8');
|
|
163
|
+
userSection = extractUserSection(existingContent);
|
|
164
|
+
if (userSection) {
|
|
165
|
+
logger.verbose('📋 Found user-customized section between markers');
|
|
166
|
+
}
|
|
167
|
+
// Also extract custom jobs (for force mode preservation)
|
|
168
|
+
const existingDoc = parseDocument(existingContent);
|
|
169
|
+
const existingJobs = existingDoc.contents && existingDoc.contents.get
|
|
170
|
+
? existingDoc.contents.get('jobs')
|
|
171
|
+
: null;
|
|
172
|
+
const managedJobs = new Set([
|
|
173
|
+
'changes',
|
|
174
|
+
'version',
|
|
175
|
+
'gate',
|
|
176
|
+
'tag',
|
|
177
|
+
'promote',
|
|
178
|
+
'release',
|
|
179
|
+
'test-nx'
|
|
180
|
+
]);
|
|
181
|
+
if (existingJobs && existingJobs.items) {
|
|
182
|
+
for (const pair of existingJobs.items) {
|
|
183
|
+
const keyStr = pair.key instanceof Scalar ? pair.key.value : pair.key;
|
|
184
|
+
if (!managedJobs.has(keyStr)) {
|
|
185
|
+
customJobsFromExisting.push(pair);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (customJobsFromExisting.length > 0) {
|
|
190
|
+
logger.verbose(`📋 Found ${customJobsFromExisting.length} custom job(s) to preserve`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// In force mode or new file, create fresh document to ensure correct structure
|
|
194
|
+
if (!fileExists || ctx.pinion?.force) {
|
|
195
|
+
const logMessage = !fileExists
|
|
196
|
+
? '📝 Creating new Nx pipeline'
|
|
197
|
+
: '🔄 Force mode: Rebuilding Nx pipeline from scratch';
|
|
198
|
+
logger.verbose(logMessage);
|
|
139
199
|
// Create new document with empty YAML map
|
|
140
200
|
const doc = parseDocument('{}');
|
|
201
|
+
// Ensure the root map uses block style (not flow/compact)
|
|
202
|
+
if (doc.contents && doc.contents.flow !== undefined) {
|
|
203
|
+
;
|
|
204
|
+
doc.contents.flow = false;
|
|
205
|
+
}
|
|
206
|
+
// Add header comment block to document
|
|
207
|
+
const headerComment = `=============================================================================
|
|
208
|
+
PIPECRAFT MANAGED WORKFLOW
|
|
209
|
+
=============================================================================
|
|
210
|
+
|
|
211
|
+
✅ YOU CAN CUSTOMIZE:
|
|
212
|
+
- Custom jobs between the '# <--START CUSTOM JOBS-->' and '# <--END CUSTOM JOBS-->' comment markers
|
|
213
|
+
- Workflow name
|
|
214
|
+
|
|
215
|
+
⚠️ PIPECRAFT MANAGES (do not modify):
|
|
216
|
+
- Workflow triggers, job dependencies, and conditionals
|
|
217
|
+
- Changes detection, version calculation, and tag creation
|
|
218
|
+
- CreatePR, branch management, promote, and release jobs
|
|
219
|
+
|
|
220
|
+
📌 VERSION PROMOTION BEHAVIOR:
|
|
221
|
+
- Only commits that trigger a version bump will promote to staging/main
|
|
222
|
+
- Non-versioned commits (test, build, etc.) remain on develop
|
|
223
|
+
- This keeps staging/main aligned with tagged releases
|
|
224
|
+
|
|
225
|
+
Running 'pipecraft generate' updates managed sections while preserving
|
|
226
|
+
your customizations in test/deploy/smoke-test etc jobs.
|
|
227
|
+
|
|
228
|
+
📖 Learn more: https://pipecraft.thecraftlab.dev
|
|
229
|
+
=============================================================================`;
|
|
230
|
+
doc.commentBefore = headerComment;
|
|
141
231
|
if (doc.contents) {
|
|
142
232
|
applyPathOperations(doc.contents, operations, doc);
|
|
143
233
|
}
|
|
144
|
-
|
|
234
|
+
let yamlContent = stringify(doc, {
|
|
235
|
+
lineWidth: 0, // 0 means no line width limit for scalars
|
|
236
|
+
indent: 2,
|
|
237
|
+
defaultStringType: 'PLAIN',
|
|
238
|
+
defaultKeyType: 'PLAIN',
|
|
239
|
+
minContentWidth: 0
|
|
240
|
+
});
|
|
241
|
+
// Insert user section and custom jobs after version job if they exist
|
|
242
|
+
const hasCustomContent = userSection || customJobsFromExisting.length > 0;
|
|
243
|
+
if (hasCustomContent) {
|
|
244
|
+
// Find the insertion point (after version job outputs)
|
|
245
|
+
const versionOutputsPattern = /^ {2}version:\s*\n(?:.*\n)*? {4}outputs:\s*\n\s*version:.*$/m;
|
|
246
|
+
const match = yamlContent.match(versionOutputsPattern);
|
|
247
|
+
if (match) {
|
|
248
|
+
const insertionIndex = match.index + match[0].length;
|
|
249
|
+
let contentToInsert = '';
|
|
250
|
+
// Add user section if exists
|
|
251
|
+
if (userSection) {
|
|
252
|
+
contentToInsert += `# <--START CUSTOM JOBS-->\n\n${userSection}\n\n # <--END CUSTOM JOBS-->`;
|
|
253
|
+
}
|
|
254
|
+
// Add custom jobs if they exist (and weren't in user section)
|
|
255
|
+
if (customJobsFromExisting.length > 0 && !userSection) {
|
|
256
|
+
const customJobsYaml = customJobsFromExisting
|
|
257
|
+
.map(pair => {
|
|
258
|
+
const keyStr = pair.key instanceof Scalar ? pair.key.value : pair.key;
|
|
259
|
+
const valueYaml = stringify(pair.value, { indent: 2 });
|
|
260
|
+
return ` ${keyStr}:\n${valueYaml
|
|
261
|
+
.split('\n')
|
|
262
|
+
.map((line) => (line ? ' ' + line : line))
|
|
263
|
+
.join('\n')}`;
|
|
264
|
+
})
|
|
265
|
+
.join('\n\n');
|
|
266
|
+
contentToInsert = `# <--START CUSTOM JOBS-->\n\n${customJobsYaml}\n\n # <--END CUSTOM JOBS-->`;
|
|
267
|
+
}
|
|
268
|
+
if (contentToInsert) {
|
|
269
|
+
yamlContent =
|
|
270
|
+
yamlContent.slice(0, insertionIndex) +
|
|
271
|
+
'\n\n ' +
|
|
272
|
+
contentToInsert +
|
|
273
|
+
'\n' +
|
|
274
|
+
yamlContent.slice(insertionIndex);
|
|
275
|
+
logger.verbose('📋 Inserted user-customized section after version job');
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
logger.verbose('⚠️ Could not find version job outputs, appending user section at end');
|
|
280
|
+
const contentToInsert = userSection ||
|
|
281
|
+
(customJobsFromExisting.length > 0
|
|
282
|
+
? customJobsFromExisting
|
|
283
|
+
.map(pair => {
|
|
284
|
+
const keyStr = pair.key instanceof Scalar ? pair.key.value : pair.key;
|
|
285
|
+
const valueYaml = stringify(pair.value, { indent: 2 });
|
|
286
|
+
return ` ${keyStr}:\n${valueYaml
|
|
287
|
+
.split('\n')
|
|
288
|
+
.map((line) => (line ? ' ' + line : line))
|
|
289
|
+
.join('\n')}`;
|
|
290
|
+
})
|
|
291
|
+
.join('\n\n')
|
|
292
|
+
: '');
|
|
293
|
+
const userSectionWithMarkers = `# <--START CUSTOM JOBS-->\n\n${contentToInsert}\n\n # <--END CUSTOM JOBS-->`;
|
|
294
|
+
yamlContent = yamlContent + '\n\n ' + userSectionWithMarkers;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
else if (!fileExists) {
|
|
298
|
+
// For new files, add placeholder markers
|
|
299
|
+
const versionOutputsPattern = /^( {2}version:\s*\n(?:.*\n)*? {4}outputs:\s*\n\s*version:.*)$/m;
|
|
300
|
+
yamlContent = yamlContent.replace(versionOutputsPattern, '$1\n\n # <--START CUSTOM JOBS-->\n\n # <--END CUSTOM JOBS-->\n');
|
|
301
|
+
logger.verbose('📝 Added placeholder user section markers');
|
|
302
|
+
}
|
|
145
303
|
const formattedContent = formatIfConditions(yamlContent);
|
|
146
|
-
|
|
304
|
+
const status = hasCustomContent ? 'merged' : fileExists ? 'rebuilt' : 'created';
|
|
305
|
+
return { ...ctx, yamlContent: formattedContent, mergeStatus: status };
|
|
147
306
|
}
|
|
148
|
-
// Parse existing file
|
|
307
|
+
// Parse existing file for merge mode (no force flag)
|
|
149
308
|
const existingContent = fs.readFileSync(filePath, 'utf8');
|
|
150
309
|
const doc = parseDocument(existingContent);
|
|
151
310
|
// Get managed jobs (always overwritten)
|
|
152
|
-
const managedJobs = new Set(['changes', '
|
|
153
|
-
//
|
|
154
|
-
|
|
311
|
+
const managedJobs = new Set(['changes', 'version', 'tag', 'promote', 'release', 'test-nx']);
|
|
312
|
+
// test-nx is preserved (user can customize), but still managed if it doesn't exist
|
|
313
|
+
// Extract custom jobs (not managed and not in user section between markers)
|
|
155
314
|
const existingJobs = doc.contents && doc.contents.get ? doc.contents.get('jobs') : null;
|
|
315
|
+
const customJobs = [];
|
|
156
316
|
if (existingJobs && existingJobs.items) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
317
|
+
// Preserve jobs that are not managed
|
|
318
|
+
for (const pair of existingJobs.items) {
|
|
319
|
+
const keyStr = pair.key instanceof Scalar ? pair.key.value : pair.key;
|
|
320
|
+
if (!managedJobs.has(keyStr)) {
|
|
321
|
+
customJobs.push(pair);
|
|
162
322
|
}
|
|
163
323
|
}
|
|
164
|
-
|
|
165
|
-
// Clear all jobs before applying operations to prevent duplicates
|
|
166
|
-
if (existingJobs && existingJobs.items) {
|
|
324
|
+
// Clear all jobs before applying operations to prevent duplicates
|
|
167
325
|
;
|
|
168
326
|
existingJobs.items = [];
|
|
169
327
|
}
|
|
@@ -171,24 +329,73 @@ export const generate = (ctx) => Promise.resolve(ctx)
|
|
|
171
329
|
if (doc.contents) {
|
|
172
330
|
applyPathOperations(doc.contents, operations, doc);
|
|
173
331
|
}
|
|
174
|
-
//
|
|
175
|
-
if (
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
332
|
+
// Reinsert custom jobs (preserved from existing pipeline)
|
|
333
|
+
if (existingJobs && customJobs.length > 0) {
|
|
334
|
+
for (const customPair of customJobs) {
|
|
335
|
+
existingJobs.add(customPair);
|
|
336
|
+
}
|
|
337
|
+
logger.verbose(`📋 Preserved ${customJobs.length} custom job(s) from existing pipeline`);
|
|
338
|
+
}
|
|
339
|
+
let yamlContent = stringify(doc, {
|
|
340
|
+
lineWidth: 0,
|
|
341
|
+
indent: 2,
|
|
342
|
+
defaultStringType: 'PLAIN',
|
|
343
|
+
defaultKeyType: 'PLAIN',
|
|
344
|
+
minContentWidth: 0
|
|
345
|
+
});
|
|
346
|
+
// Insert user section after version job if it exists
|
|
347
|
+
if (userSection) {
|
|
348
|
+
const versionOutputsPattern = /^ {2}version:\s*\n(?:.*\n)*? {4}outputs:\s*\n\s*version:.*$/m;
|
|
349
|
+
const match = yamlContent.match(versionOutputsPattern);
|
|
350
|
+
if (match) {
|
|
351
|
+
const insertionIndex = match.index + match[0].length;
|
|
352
|
+
const userSectionWithMarkers = `# <--START CUSTOM JOBS-->\n\n${userSection}\n\n # <--END CUSTOM JOBS-->`;
|
|
353
|
+
yamlContent =
|
|
354
|
+
yamlContent.slice(0, insertionIndex) +
|
|
355
|
+
'\n\n ' +
|
|
356
|
+
userSectionWithMarkers +
|
|
357
|
+
'\n' +
|
|
358
|
+
yamlContent.slice(insertionIndex);
|
|
359
|
+
logger.verbose('📋 Inserted user-customized section after version job');
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
// Also insert custom jobs that weren't in the user section
|
|
363
|
+
if (customJobs.length > 0 && !userSection) {
|
|
364
|
+
const versionOutputsPattern = /^ {2}version:\s*\n(?:.*\n)*? {4}outputs:\s*\n\s*version:.*$/m;
|
|
365
|
+
const match = yamlContent.match(versionOutputsPattern);
|
|
366
|
+
if (match) {
|
|
367
|
+
const insertionIndex = match.index + match[0].length;
|
|
368
|
+
const customJobsYaml = customJobs
|
|
369
|
+
.map(pair => {
|
|
370
|
+
const keyStr = pair.key instanceof Scalar ? pair.key.value : pair.key;
|
|
371
|
+
const valueYaml = stringify(pair.value, { indent: 2 });
|
|
372
|
+
return ` ${keyStr}:\n${valueYaml
|
|
373
|
+
.split('\n')
|
|
374
|
+
.map((line) => (line ? ' ' + line : line))
|
|
375
|
+
.join('\n')}`;
|
|
376
|
+
})
|
|
377
|
+
.join('\n\n');
|
|
378
|
+
yamlContent =
|
|
379
|
+
yamlContent.slice(0, insertionIndex) +
|
|
380
|
+
'\n\n # <--START CUSTOM JOBS-->\n\n' +
|
|
381
|
+
customJobsYaml +
|
|
382
|
+
'\n\n # <--END CUSTOM JOBS-->\n' +
|
|
383
|
+
yamlContent.slice(insertionIndex);
|
|
182
384
|
}
|
|
183
385
|
}
|
|
184
|
-
const status =
|
|
185
|
-
const yamlContent = stringify(doc, { lineWidth: 0, minContentWidth: 0 });
|
|
386
|
+
const status = userSection || customJobs.length > 0 ? 'merged' : 'updated';
|
|
186
387
|
const formattedContent = formatIfConditions(yamlContent);
|
|
187
388
|
return { ...ctx, yamlContent: formattedContent, mergeStatus: status };
|
|
188
389
|
})
|
|
189
390
|
.then(ctx => {
|
|
190
391
|
const outputPath = ctx.outputPipelinePath || '.github/workflows/pipeline.yml';
|
|
191
|
-
const status = ctx.mergeStatus === 'merged'
|
|
392
|
+
const status = ctx.mergeStatus === 'merged'
|
|
393
|
+
? '🔄 Merged with existing'
|
|
394
|
+
: ctx.mergeStatus === 'updated'
|
|
395
|
+
? '🔄 Updated existing'
|
|
396
|
+
: ctx.mergeStatus === 'rebuilt'
|
|
397
|
+
? '🔄 Rebuilt from scratch'
|
|
398
|
+
: '📝 Created new';
|
|
192
399
|
logger.verbose(`${status} ${outputPath}`);
|
|
193
400
|
return ctx;
|
|
194
401
|
})
|