gowalk-cicd 1.0.170 → 1.0.171
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/docs/CONFIGURATION.md +9 -0
- package/package.json +1 -1
- package/src/config/merge.mjs +45 -1
package/docs/CONFIGURATION.md
CHANGED
|
@@ -99,3 +99,12 @@ An unknown layout or overlapping custom code edit returns a JSON
|
|
|
99
99
|
`gowalk-cicd/migration-repair.v1` receipt with its code, file and YAML path. The
|
|
100
100
|
receipt never includes the conflicting value. Resolve that specific customization
|
|
101
101
|
in the same repository; unrelated repositories can continue upgrading.
|
|
102
|
+
|
|
103
|
+
1.0.168 deleted the Android `mode` step (Bitrise delivery). No app enabled Bitrise, so it
|
|
104
|
+
always answered `local`; a deleted step answers null. An upgrade therefore drops a
|
|
105
|
+
`steps.mode.outputs.mode == 'local'` (or `!= 'bitrise'`) conjunct from an app's
|
|
106
|
+
`jobs.android` step `if`, and an `if` left empty goes. Any other use of `steps.mode` in a
|
|
107
|
+
`jobs.android` step `if` returns `android_mode_condition_requires_edit`: a Bitrise-only step
|
|
108
|
+
never ran (delete it), and beside `always()`, `failure()` or `cancelled()` the conjunct also
|
|
109
|
+
meant that the steps before `mode` succeeded (restate that). `env`, `run` and job outputs are
|
|
110
|
+
not checked; there `steps.mode` renders empty.
|
package/package.json
CHANGED
package/src/config/merge.mjs
CHANGED
|
@@ -86,9 +86,53 @@ function iosChange(file, before, after, change) {
|
|
|
86
86
|
return change;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
// 1.0.168 deleted the Android step `mode`, which answered 'local' on every app (none enabled
|
|
90
|
+
// Bitrise). A missing step answers null, so an app step still guarded by
|
|
91
|
+
// `steps.mode.outputs.mode == 'local'` silently stopped running. That always-true conjunct is
|
|
92
|
+
// dropped (&& binds tighter than ||, so any isolated conjunct can go); any other use refuses.
|
|
93
|
+
// Beside always(), failure() or cancelled() it also meant "nothing before mode failed", so it refuses.
|
|
94
|
+
const MODE = /^steps\.mode\.outputs\.mode\s*(?:==\s*'local'|!=\s*'bitrise')$/;
|
|
95
|
+
const USES_MODE = /\bsteps\.mode(?![\w-])/, STATUS = /\b(?:always|failure|cancelled)\(/;
|
|
96
|
+
|
|
97
|
+
function conjuncts(body) {
|
|
98
|
+
const terms = [];
|
|
99
|
+
let depth = 0, quoted = false, start = 0;
|
|
100
|
+
for (let index = 0; index < body.length; index++) {
|
|
101
|
+
const char = body[index];
|
|
102
|
+
if (char === "'") quoted = !quoted;
|
|
103
|
+
else if (!quoted && (char === '(' || char === ')')) depth += char === '(' ? 1 : -1;
|
|
104
|
+
else if (!quoted && !depth && body.startsWith('&&', index)) {
|
|
105
|
+
terms.push(body.slice(start, index).trim());
|
|
106
|
+
start = ++index + 1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return [...terms, body.slice(start).trim()];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function modeChange(file, change, ownMode) {
|
|
113
|
+
const [jobs, job, steps, items, name, key] = change.path;
|
|
114
|
+
if (file !== 'deploy.yml' || jobs !== 'jobs' || job !== 'android' || steps !== 'steps' || items !== 'items'
|
|
115
|
+
|| ownMode) return change;
|
|
116
|
+
const step = change.path.length === 5 && change.value && typeof change.value === 'object';
|
|
117
|
+
const condition = step ? change.value.if : change.path.length === 6 && key === 'if' ? change.value : null;
|
|
118
|
+
if (typeof condition !== 'string' || !USES_MODE.test(condition)) return change;
|
|
119
|
+
const terms = conjuncts(condition.trim().replace(/^\$\{\{([\s\S]*)\}\}$/, '$1').trim())
|
|
120
|
+
.filter(term => !MODE.test(term));
|
|
121
|
+
if (terms.some(term => USES_MODE.test(term) || STATUS.test(term))) {
|
|
122
|
+
throw new MigrationRepair('android_mode_condition_requires_edit', file, change.path);
|
|
123
|
+
}
|
|
124
|
+
console.log(` Migrated ${file} android step ${name}: dropped steps.mode (step deleted in 1.0.168)`);
|
|
125
|
+
const migrated = terms.length ? `\${{ ${terms.join(' && ')} }}` : undefined;
|
|
126
|
+
if (!step) return migrated === undefined ? { path: change.path, remove: true } : { ...change, value: migrated };
|
|
127
|
+
return { ...change, value: Object.fromEntries(Object.entries(change.value).flatMap(([field, value]) =>
|
|
128
|
+
field !== 'if' ? [[field, value]] : migrated === undefined ? [] : [[field, migrated]])) };
|
|
129
|
+
}
|
|
130
|
+
|
|
89
131
|
export function mergeChanges(base, incoming, changes, file) {
|
|
90
132
|
const result = structuredClone(incoming);
|
|
91
|
-
|
|
133
|
+
const ownMode = changes.some(change => equal(change.path, ['jobs', 'android', 'steps', 'items', 'id:mode']));
|
|
134
|
+
for (const raw of changes) {
|
|
135
|
+
const change = modeChange(file, raw, ownMode);
|
|
92
136
|
const before = at(base, change.path), after = at(incoming, change.path);
|
|
93
137
|
if (change.path.at(-1) === 'order' && Array.isArray(before) && Array.isArray(after)) {
|
|
94
138
|
assign(result, { path: change.path, value: mergeOrder(before, change.value, after, file, change.path) });
|