@fuzdev/fuz_gitops 0.78.1 → 0.79.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 +78 -24
- package/dist/ModulesDetail.svelte +15 -22
- package/dist/ModulesDetail.svelte.d.ts.map +1 -1
- package/dist/ModulesNav.svelte +4 -1
- package/dist/ModulesPage.svelte +1 -3
- package/dist/ModulesPage.svelte.d.ts.map +1 -1
- package/dist/PageHeader.svelte +2 -2
- package/dist/PageHeader.svelte.d.ts +0 -3
- package/dist/PageHeader.svelte.d.ts.map +1 -1
- package/dist/PullRequestsDetail.svelte +10 -9
- package/dist/PullRequestsDetail.svelte.d.ts.map +1 -1
- package/dist/PullRequestsPage.svelte +1 -3
- package/dist/PullRequestsPage.svelte.d.ts.map +1 -1
- package/dist/ReposTable.svelte +27 -48
- package/dist/ReposTable.svelte.d.ts.map +1 -1
- package/dist/ReposTree.svelte +5 -19
- package/dist/ReposTree.svelte.d.ts.map +1 -1
- package/dist/ReposTreeNav.svelte +5 -7
- package/dist/ReposTreeNav.svelte.d.ts.map +1 -1
- package/dist/TablePage.svelte +1 -3
- package/dist/TablePage.svelte.d.ts.map +1 -1
- package/dist/TreeItemPage.svelte +1 -3
- package/dist/TreeItemPage.svelte.d.ts.map +1 -1
- package/dist/TreePage.svelte +1 -3
- package/dist/TreePage.svelte.d.ts.map +1 -1
- package/dist/ci_reconcile.d.ts +6 -10
- package/dist/ci_reconcile.d.ts.map +1 -1
- package/dist/ci_reconcile.js +6 -8
- package/dist/dependency_graph.d.ts +26 -49
- package/dist/dependency_graph.d.ts.map +1 -1
- package/dist/dependency_graph.js +37 -80
- package/dist/dependency_updater.d.ts +1 -1
- package/dist/dependency_updater.d.ts.map +1 -1
- package/dist/dependency_updater.js +6 -1
- package/dist/fetch_repo_data.d.ts +34 -8
- package/dist/fetch_repo_data.d.ts.map +1 -1
- package/dist/fetch_repo_data.js +44 -22
- package/dist/fs_fetch_value_cache.d.ts +1 -1
- package/dist/fs_fetch_value_cache.js +1 -1
- package/dist/git_operations.d.ts +6 -49
- package/dist/git_operations.d.ts.map +1 -1
- package/dist/git_operations.js +13 -126
- package/dist/github.d.ts +17 -2
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +15 -6
- package/dist/github_helpers.d.ts.map +1 -1
- package/dist/github_helpers.js +3 -11
- package/dist/gitops_analyze.task.d.ts +24 -2
- package/dist/gitops_analyze.task.d.ts.map +1 -1
- package/dist/gitops_analyze.task.js +43 -30
- package/dist/gitops_config.d.ts +34 -79
- package/dist/gitops_config.d.ts.map +1 -1
- package/dist/gitops_config.js +76 -53
- package/dist/gitops_constants.d.ts +6 -4
- package/dist/gitops_constants.d.ts.map +1 -1
- package/dist/gitops_constants.js +6 -4
- package/dist/gitops_plan.task.d.ts +29 -3
- package/dist/gitops_plan.task.d.ts.map +1 -1
- package/dist/gitops_plan.task.js +80 -58
- package/dist/gitops_publish.task.d.ts +62 -2
- package/dist/gitops_publish.task.d.ts.map +1 -1
- package/dist/gitops_publish.task.js +187 -102
- package/dist/gitops_run.task.d.ts +74 -0
- package/dist/gitops_run.task.d.ts.map +1 -1
- package/dist/gitops_run.task.js +174 -160
- package/dist/gitops_sync.task.d.ts +65 -3
- package/dist/gitops_sync.task.d.ts.map +1 -1
- package/dist/gitops_sync.task.js +154 -30
- package/dist/gitops_task_helpers.d.ts +86 -59
- package/dist/gitops_task_helpers.d.ts.map +1 -1
- package/dist/gitops_task_helpers.js +120 -79
- package/dist/gitops_validate.task.d.ts +1 -2
- package/dist/gitops_validate.task.d.ts.map +1 -1
- package/dist/gitops_validate.task.js +15 -22
- package/dist/graph_validation.d.ts +16 -27
- package/dist/graph_validation.d.ts.map +1 -1
- package/dist/graph_validation.js +23 -64
- package/dist/local_repo.d.ts +50 -62
- package/dist/local_repo.d.ts.map +1 -1
- package/dist/local_repo.js +80 -193
- package/dist/log_helpers.d.ts +8 -8
- package/dist/log_helpers.d.ts.map +1 -1
- package/dist/multi_repo_publisher.d.ts +10 -0
- package/dist/multi_repo_publisher.d.ts.map +1 -1
- package/dist/multi_repo_publisher.js +115 -51
- package/dist/npm_registry.d.ts +23 -19
- package/dist/npm_registry.d.ts.map +1 -1
- package/dist/npm_registry.js +20 -47
- package/dist/operations.d.ts +75 -180
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +15 -7
- package/dist/operations_defaults.d.ts +17 -2
- package/dist/operations_defaults.d.ts.map +1 -1
- package/dist/operations_defaults.js +104 -121
- package/dist/output_helpers.d.ts +36 -0
- package/dist/output_helpers.d.ts.map +1 -1
- package/dist/output_helpers.js +37 -3
- package/dist/preflight_checks.d.ts +20 -27
- package/dist/preflight_checks.d.ts.map +1 -1
- package/dist/preflight_checks.js +37 -126
- package/dist/publish_steps.d.ts +2 -4
- package/dist/publish_steps.d.ts.map +1 -1
- package/dist/publish_steps.js +2 -6
- package/dist/publishing_event.d.ts +2 -8
- package/dist/publishing_event.d.ts.map +1 -1
- package/dist/publishing_event.js +5 -4
- package/dist/publishing_event_handler.d.ts +10 -8
- package/dist/publishing_event_handler.d.ts.map +1 -1
- package/dist/publishing_event_handler.js +14 -12
- package/dist/publishing_plan.d.ts +16 -1
- package/dist/publishing_plan.d.ts.map +1 -1
- package/dist/publishing_plan.js +328 -250
- package/dist/publishing_plan_logging.d.ts +1 -1
- package/dist/publishing_plan_logging.d.ts.map +1 -1
- package/dist/publishing_plan_logging.js +21 -14
- package/dist/repo.svelte.d.ts +7 -0
- package/dist/repo.svelte.d.ts.map +1 -1
- package/dist/repo.svelte.js +3 -0
- package/dist/repo_readiness.d.ts +210 -0
- package/dist/repo_readiness.d.ts.map +1 -0
- package/dist/repo_readiness.js +516 -0
- package/dist/repos_status.d.ts +3340 -0
- package/dist/repos_status.d.ts.map +1 -0
- package/dist/repos_status.js +555 -0
- package/dist/repos_status_load.d.ts +65 -0
- package/dist/repos_status_load.d.ts.map +1 -0
- package/dist/repos_status_load.js +131 -0
- package/package.json +7 -27
- package/src/lib/ci_reconcile.ts +7 -11
- package/src/lib/dependency_graph.ts +45 -97
- package/src/lib/dependency_updater.ts +7 -1
- package/src/lib/fetch_repo_data.ts +66 -29
- package/src/lib/fs_fetch_value_cache.ts +1 -1
- package/src/lib/git_operations.ts +15 -187
- package/src/lib/github.ts +20 -8
- package/src/lib/github_helpers.ts +5 -12
- package/src/lib/gitops_analyze.task.ts +79 -41
- package/src/lib/gitops_config.ts +88 -137
- package/src/lib/gitops_constants.ts +6 -4
- package/src/lib/gitops_plan.task.ts +113 -61
- package/src/lib/gitops_publish.task.ts +255 -122
- package/src/lib/gitops_run.task.ts +250 -178
- package/src/lib/gitops_sync.task.ts +208 -33
- package/src/lib/gitops_task_helpers.ts +166 -110
- package/src/lib/gitops_validate.task.ts +17 -27
- package/src/lib/graph_validation.ts +25 -86
- package/src/lib/local_repo.ts +109 -316
- package/src/lib/log_helpers.ts +8 -18
- package/src/lib/multi_repo_publisher.ts +138 -53
- package/src/lib/npm_registry.ts +37 -62
- package/src/lib/operations.ts +78 -150
- package/src/lib/operations_defaults.ts +108 -154
- package/src/lib/output_helpers.ts +55 -3
- package/src/lib/preflight_checks.ts +47 -183
- package/src/lib/publish_steps.ts +15 -13
- package/src/lib/publishing_event.ts +5 -4
- package/src/lib/publishing_event_handler.ts +18 -16
- package/src/lib/publishing_plan.ts +451 -287
- package/src/lib/publishing_plan_logging.ts +32 -23
- package/src/lib/repo.svelte.ts +8 -0
- package/src/lib/repo_readiness.ts +647 -0
- package/src/lib/repos_status.ts +671 -0
- package/src/lib/repos_status_load.ts +173 -0
- package/dist/config_reconcile.d.ts +0 -46
- package/dist/config_reconcile.d.ts.map +0 -1
- package/dist/config_reconcile.js +0 -64
- package/dist/paths.d.ts +0 -7
- package/dist/paths.d.ts.map +0 -1
- package/dist/paths.js +0 -6
- package/dist/repo_ops.d.ts +0 -59
- package/dist/repo_ops.d.ts.map +0 -1
- package/dist/repo_ops.js +0 -170
- package/dist/resolved_gitops_config.d.ts +0 -9
- package/dist/resolved_gitops_config.d.ts.map +0 -1
- package/dist/resolved_gitops_config.js +0 -12
- package/src/lib/config_reconcile.ts +0 -98
- package/src/lib/paths.ts +0 -6
- package/src/lib/repo_ops.ts +0 -216
- package/src/lib/resolved_gitops_config.ts +0 -27
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Production implementations of operations interfaces.
|
|
3
3
|
*
|
|
4
|
-
* Provides real git, npm, fs, and
|
|
4
|
+
* Provides real git, npm, fs, build, and `repos` operations for production use.
|
|
5
5
|
* For interface definitions and dependency injection pattern, see `operations.ts`.
|
|
6
6
|
*
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
|
-
import { spawn_out } from '@fuzdev/fuz_util/process.ts';
|
|
9
|
+
import { spawn_out, spawn_process, spawn_result_to_message } from '@fuzdev/fuz_util/process.ts';
|
|
10
10
|
import { readFile, writeFile, mkdir, stat } from 'node:fs/promises';
|
|
11
|
-
import {
|
|
11
|
+
import { stripVTControlCharacters } from 'node:util';
|
|
12
12
|
import { fs_classify_error } from '@fuzdev/fuz_util/fs.ts';
|
|
13
13
|
import { EMPTY_OBJECT } from '@fuzdev/fuz_util/object.ts';
|
|
14
14
|
import { has_changesets, read_changesets, predict_next_version } from './changeset_reader.js';
|
|
15
15
|
import { wait_for_package } from './npm_registry.js';
|
|
16
16
|
import { run_preflight_checks } from './preflight_checks.js';
|
|
17
|
-
import { git_add, git_commit,
|
|
17
|
+
import { git_add, git_commit, git_current_commit_hash_required } from './git_operations.js';
|
|
18
18
|
/** Wrap an async function that returns a value */
|
|
19
19
|
const wrap_with_value = async (fn) => {
|
|
20
20
|
try {
|
|
@@ -59,119 +59,113 @@ export const default_changeset_operations = {
|
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
61
|
export const default_git_operations = {
|
|
62
|
-
// Core git info
|
|
63
|
-
current_branch_name: async (options) => {
|
|
64
|
-
const { cwd } = options ?? EMPTY_OBJECT;
|
|
65
|
-
return wrap_with_value(() => git_current_branch_name_required(cwd ? { cwd } : undefined));
|
|
66
|
-
},
|
|
67
62
|
current_commit_hash: async (options) => {
|
|
68
|
-
const { branch, cwd } = options ?? EMPTY_OBJECT;
|
|
69
|
-
return wrap_with_value(() => git_current_commit_hash_required(branch, cwd ? { cwd } : undefined));
|
|
70
|
-
},
|
|
71
|
-
check_clean_workspace: async (options) => {
|
|
72
63
|
const { cwd } = options ?? EMPTY_OBJECT;
|
|
73
|
-
return wrap_with_value(() =>
|
|
74
|
-
},
|
|
75
|
-
// Branch operations
|
|
76
|
-
checkout: async (options) => {
|
|
77
|
-
const { branch, cwd } = options;
|
|
78
|
-
return wrap_void(() => git_checkout(branch, cwd ? { cwd } : undefined));
|
|
79
|
-
},
|
|
80
|
-
pull: async (options) => {
|
|
81
|
-
const { origin, branch, cwd } = options ?? EMPTY_OBJECT;
|
|
82
|
-
try {
|
|
83
|
-
// Omit the branch arg when absent: a trailing `''` makes git pull the remote's
|
|
84
|
-
// default branch (origin/HEAD) instead of the current branch's upstream.
|
|
85
|
-
const spawned = await spawn_out('git', ['pull', origin || 'origin', ...(branch ? [branch] : [])], cwd ? { cwd } : undefined);
|
|
86
|
-
if (spawned.result.ok) {
|
|
87
|
-
return { ok: true };
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
return { ok: false, message: spawned.stderr || 'Pull failed' };
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
catch (error) {
|
|
94
|
-
return { ok: false, message: String(error) };
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
switch_branch: async (options) => {
|
|
98
|
-
const { branch, pull, cwd } = options;
|
|
99
|
-
return wrap_void(() => git_switch_branch(branch, pull, cwd ? { cwd } : undefined));
|
|
64
|
+
return wrap_with_value(() => git_current_commit_hash_required(cwd ? { cwd } : undefined));
|
|
100
65
|
},
|
|
101
|
-
has_remote: async (options) => {
|
|
102
|
-
const { remote, cwd } = options ?? EMPTY_OBJECT;
|
|
103
|
-
return wrap_with_value(() => git_has_remote(remote, cwd ? { cwd } : undefined));
|
|
104
|
-
},
|
|
105
|
-
// Staging and committing
|
|
106
66
|
add: async (options) => {
|
|
107
67
|
const { files, cwd } = options;
|
|
108
68
|
return wrap_void(() => git_add(files, cwd ? { cwd } : undefined));
|
|
109
69
|
},
|
|
110
70
|
commit: async (options) => {
|
|
111
|
-
const { message, cwd } = options;
|
|
112
|
-
return wrap_void(() => git_commit(message, cwd ? { cwd } : undefined));
|
|
113
|
-
},
|
|
114
|
-
add_and_commit: async (options) => {
|
|
115
|
-
const { files, message, cwd } = options;
|
|
116
|
-
return wrap_void(() => git_add_and_commit(files, message, cwd ? { cwd } : undefined));
|
|
117
|
-
},
|
|
118
|
-
has_changes: async (options) => {
|
|
119
|
-
const { cwd } = options ?? EMPTY_OBJECT;
|
|
120
|
-
return wrap_with_value(() => git_has_changes(cwd ? { cwd } : undefined));
|
|
121
|
-
},
|
|
122
|
-
list_uncommitted_files: async (options) => {
|
|
123
|
-
const { cwd } = options ?? EMPTY_OBJECT;
|
|
124
|
-
return wrap_with_value(() => git_list_uncommitted_files(cwd ? { cwd } : undefined));
|
|
125
|
-
},
|
|
126
|
-
// Tagging
|
|
127
|
-
tag: async (options) => {
|
|
128
|
-
const { tag_name, message, cwd } = options;
|
|
129
|
-
return wrap_void(() => git_tag(tag_name, message, cwd ? { cwd } : undefined));
|
|
130
|
-
},
|
|
131
|
-
push_tag: async (options) => {
|
|
132
|
-
const { tag_name, origin, cwd } = options;
|
|
133
|
-
return wrap_void(() => git_push_tag(tag_name, origin, cwd ? { cwd } : undefined));
|
|
134
|
-
},
|
|
135
|
-
// Stashing
|
|
136
|
-
stash: async (options) => {
|
|
137
|
-
const { message, cwd } = options ?? EMPTY_OBJECT;
|
|
138
|
-
return wrap_void(() => git_stash(message, cwd ? { cwd } : undefined));
|
|
139
|
-
},
|
|
140
|
-
stash_pop: async (options) => {
|
|
141
|
-
const { cwd } = options ?? EMPTY_OBJECT;
|
|
142
|
-
return wrap_void(() => git_stash_pop(cwd ? { cwd } : undefined));
|
|
143
|
-
},
|
|
144
|
-
// File change detection
|
|
145
|
-
has_file_changed: async (options) => {
|
|
146
|
-
const { from_commit, to_commit, file_path, cwd } = options;
|
|
147
|
-
return wrap_with_value(() => git_has_file_changed(from_commit, to_commit, file_path, cwd ? { cwd } : undefined));
|
|
71
|
+
const { message, files, cwd } = options;
|
|
72
|
+
return wrap_void(() => git_commit(message, files, cwd ? { cwd } : undefined));
|
|
148
73
|
}
|
|
149
74
|
};
|
|
75
|
+
/** The most lines of a child's stderr a failure carries. */
|
|
76
|
+
export const OUTPUT_TAIL_MAX_LINES = 20;
|
|
77
|
+
/** The most characters of a child's stderr a failure carries. */
|
|
78
|
+
export const OUTPUT_TAIL_MAX_CHARS = 4096;
|
|
79
|
+
/**
|
|
80
|
+
* The end of a process's output, for a failure message: its last lines, then
|
|
81
|
+
* its last characters, with terminal escape sequences stripped and trailing
|
|
82
|
+
* whitespace trimmed.
|
|
83
|
+
*
|
|
84
|
+
* @param text - the output, or as much of its end as was kept
|
|
85
|
+
* @param max_lines - the most lines to keep
|
|
86
|
+
* @param max_chars - the most characters to keep, applied after `max_lines`
|
|
87
|
+
*/
|
|
88
|
+
export const output_tail = (text, max_lines = OUTPUT_TAIL_MAX_LINES, max_chars = OUTPUT_TAIL_MAX_CHARS) => {
|
|
89
|
+
const lines = stripVTControlCharacters(text).replace(/\r\n?/g, '\n').trimEnd().split('\n');
|
|
90
|
+
const tail = lines.slice(-max_lines).join('\n');
|
|
91
|
+
if (tail.length <= max_chars)
|
|
92
|
+
return drop_leading_blank_lines(tail);
|
|
93
|
+
// a character cut can split a line, and with it a secret masking would no longer
|
|
94
|
+
// recognize, so the partial first line goes
|
|
95
|
+
const cut = tail.slice(-max_chars);
|
|
96
|
+
if (tail[tail.length - max_chars - 1] === '\n')
|
|
97
|
+
return drop_leading_blank_lines(cut);
|
|
98
|
+
const nl = cut.indexOf('\n');
|
|
99
|
+
return nl === -1 ? '' : drop_leading_blank_lines(cut.slice(nl + 1));
|
|
100
|
+
};
|
|
101
|
+
// not `trimStart`, which would strip the first line's indentation
|
|
102
|
+
const drop_leading_blank_lines = (text) => text.replace(/^\n+/, '');
|
|
150
103
|
export const default_process_operations = {
|
|
151
|
-
|
|
152
|
-
const { cmd, args, cwd } = options;
|
|
104
|
+
run_interactive: async (options) => {
|
|
105
|
+
const { cmd, args, cwd, stdout = 'stdout' } = options;
|
|
153
106
|
try {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
107
|
+
// stdin and stdout go straight to the child (fd 2 for stdout routed to our stderr), so
|
|
108
|
+
// they stay a TTY when ours are — npm prompts for a one-time password only on a TTY.
|
|
109
|
+
// Only stderr is piped, to keep its end for the failure message while echoing it live.
|
|
110
|
+
const { child, closed } = spawn_process(cmd, args, {
|
|
111
|
+
cwd,
|
|
112
|
+
stdio: ['inherit', stdout === 'stderr' ? 2 : 'inherit', 'pipe']
|
|
113
|
+
});
|
|
114
|
+
// a rolling window over stderr's end, bounded however much the child writes
|
|
115
|
+
let kept = '';
|
|
116
|
+
child.stderr?.setEncoding('utf8');
|
|
117
|
+
child.stderr?.on('data', (chunk) => {
|
|
118
|
+
process.stderr.write(chunk);
|
|
119
|
+
kept += chunk;
|
|
120
|
+
if (kept.length > OUTPUT_TAIL_MAX_CHARS * 4)
|
|
121
|
+
kept = kept.slice(-OUTPUT_TAIL_MAX_CHARS * 2);
|
|
122
|
+
});
|
|
123
|
+
const result = await closed;
|
|
124
|
+
if (result.ok)
|
|
125
|
+
return { ok: true };
|
|
126
|
+
const stderr_tail = output_tail(kept);
|
|
127
|
+
return {
|
|
128
|
+
ok: false,
|
|
129
|
+
message: `\`${[cmd, ...args].join(' ')}\` failed (${spawn_result_to_message(result)})`,
|
|
130
|
+
stderr_tail: stderr_tail || undefined
|
|
131
|
+
};
|
|
169
132
|
}
|
|
170
133
|
catch (error) {
|
|
171
134
|
return { ok: false, message: String(error) };
|
|
172
135
|
}
|
|
173
136
|
}
|
|
174
137
|
};
|
|
138
|
+
export const default_repos_operations = {
|
|
139
|
+
status: async (options) => {
|
|
140
|
+
const { keys, registry, fetch } = options;
|
|
141
|
+
const args = [...(registry === undefined ? [] : ['--registry', registry]), 'status'];
|
|
142
|
+
if (fetch)
|
|
143
|
+
args.push('--fetch');
|
|
144
|
+
// `--` so a key can never read as a flag
|
|
145
|
+
args.push('--json', '--', ...keys);
|
|
146
|
+
const spawned = await spawn_out('repos', args);
|
|
147
|
+
const { result } = spawned;
|
|
148
|
+
if (result.kind === 'error') {
|
|
149
|
+
const not_found = result.error.code === 'ENOENT';
|
|
150
|
+
return {
|
|
151
|
+
ok: false,
|
|
152
|
+
kind: not_found ? 'not_found' : 'failed',
|
|
153
|
+
message: result.error.message
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (result.kind === 'signaled') {
|
|
157
|
+
return { ok: false, kind: 'failed', message: `repos was killed by ${result.signal}` };
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
ok: true,
|
|
161
|
+
output: {
|
|
162
|
+
stdout: spawned.stdout ?? '',
|
|
163
|
+
stderr: spawned.stderr ?? '',
|
|
164
|
+
exit_code: result.code
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
};
|
|
175
169
|
export const default_npm_operations = {
|
|
176
170
|
wait_for_package: async (options) => {
|
|
177
171
|
const { pkg, version, wait_options, log } = options;
|
|
@@ -180,7 +174,7 @@ export const default_npm_operations = {
|
|
|
180
174
|
return { ok: true };
|
|
181
175
|
}
|
|
182
176
|
catch (error) {
|
|
183
|
-
return { ok: false, message: String(error)
|
|
177
|
+
return { ok: false, message: String(error) };
|
|
184
178
|
}
|
|
185
179
|
},
|
|
186
180
|
check_auth: async () => {
|
|
@@ -200,26 +194,15 @@ export const default_npm_operations = {
|
|
|
200
194
|
},
|
|
201
195
|
check_registry: async () => {
|
|
202
196
|
try {
|
|
203
|
-
|
|
204
|
-
|
|
197
|
+
// the exit status alone: `npm ping` reports on stderr, writing nothing to stdout
|
|
198
|
+
const { result } = await spawn_out('npm', ['ping']);
|
|
199
|
+
if (result.ok) {
|
|
205
200
|
return { ok: true };
|
|
206
201
|
}
|
|
207
|
-
return {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
install: async (options) => {
|
|
214
|
-
const { cwd } = options ?? EMPTY_OBJECT;
|
|
215
|
-
try {
|
|
216
|
-
const spawned = await spawn_out('npm', ['install'], cwd ? { cwd } : undefined);
|
|
217
|
-
if (spawned.result.ok) {
|
|
218
|
-
return { ok: true };
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
return { ok: false, message: 'Install failed', stderr: spawned.stderr || undefined };
|
|
222
|
-
}
|
|
202
|
+
return {
|
|
203
|
+
ok: false,
|
|
204
|
+
message: `Failed to ping npm registry (${spawn_result_to_message(result)})`
|
|
205
|
+
};
|
|
223
206
|
}
|
|
224
207
|
catch (error) {
|
|
225
208
|
return { ok: false, message: String(error) };
|
|
@@ -274,9 +257,8 @@ export const default_fs_operations = {
|
|
|
274
257
|
};
|
|
275
258
|
export const default_build_operations = {
|
|
276
259
|
build_package: async (options) => {
|
|
277
|
-
const { repo
|
|
260
|
+
const { repo } = options;
|
|
278
261
|
try {
|
|
279
|
-
log?.info(` Building ${repo.library.name}...`);
|
|
280
262
|
const spawned = await spawn_out('gro', ['build'], { cwd: repo.repo_dir });
|
|
281
263
|
if (spawned.result.ok) {
|
|
282
264
|
return { ok: true };
|
|
@@ -304,5 +286,6 @@ export const default_gitops_operations = {
|
|
|
304
286
|
npm: default_npm_operations,
|
|
305
287
|
preflight: default_preflight_operations,
|
|
306
288
|
fs: default_fs_operations,
|
|
307
|
-
build: default_build_operations
|
|
289
|
+
build: default_build_operations,
|
|
290
|
+
repos: default_repos_operations
|
|
308
291
|
};
|
package/dist/output_helpers.d.ts
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import type { Logger } from '@fuzdev/fuz_util/log.ts';
|
|
2
2
|
export type OutputFormat = 'stdout' | 'json' | 'markdown';
|
|
3
|
+
/**
|
|
4
|
+
* Writes one machine-readable document, or one line of a stream, to stdout,
|
|
5
|
+
* ending it with a newline.
|
|
6
|
+
*/
|
|
7
|
+
export type WriteStdout = (content: string) => void;
|
|
3
8
|
export interface OutputOptions {
|
|
4
9
|
format: OutputFormat;
|
|
5
10
|
outfile?: string;
|
|
6
11
|
log?: Logger;
|
|
12
|
+
/**
|
|
13
|
+
* Where a `json` or `markdown` document goes without `outfile`; the one
|
|
14
|
+
* `route_human_output` returns, so the document reaches stdout while the
|
|
15
|
+
* logger's lines go to stderr.
|
|
16
|
+
*
|
|
17
|
+
* @default `console.log`
|
|
18
|
+
*/
|
|
19
|
+
write_stdout?: WriteStdout;
|
|
7
20
|
}
|
|
8
21
|
export interface OutputFormatters<T> {
|
|
9
22
|
json: (data: T) => string;
|
|
@@ -13,6 +26,29 @@ export interface OutputFormatters<T> {
|
|
|
13
26
|
*/
|
|
14
27
|
stdout: (data: T, log: Logger) => void;
|
|
15
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Whether a task's stdout carries a machine-readable document: a `json` or
|
|
31
|
+
* `markdown` report not sent to `--outfile`.
|
|
32
|
+
*
|
|
33
|
+
* @param format - the task's `--format`
|
|
34
|
+
* @param outfile - the task's `--outfile`, if any
|
|
35
|
+
*/
|
|
36
|
+
export declare const output_is_machine: (format: string, outfile: string | undefined) => boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Keeps a task's stdout for its machine-readable document or stream when
|
|
39
|
+
* `machine` is set: the logger's `info` and `debug` lines, which it writes with
|
|
40
|
+
* `console.log`, go where its errors go — stderr — and child loggers inherit
|
|
41
|
+
* that. Gro hands a task the logger its own lines go through, so gro's lines
|
|
42
|
+
* after the task runs (`✓`, the timings) follow to stderr; the two it prints
|
|
43
|
+
* before the task runs (`invoking`, `→ <task>`) stay on stdout, out of the
|
|
44
|
+
* task's reach.
|
|
45
|
+
*
|
|
46
|
+
* @param log - the task's logger
|
|
47
|
+
* @param machine - whether stdout carries a machine-readable document or stream
|
|
48
|
+
* @returns writes to the stdout the logger wrote to before, for the document
|
|
49
|
+
* @mutates log - overrides its `console` when `machine` is set
|
|
50
|
+
*/
|
|
51
|
+
export declare const route_human_output: (log: Logger, machine: boolean) => WriteStdout;
|
|
16
52
|
/**
|
|
17
53
|
* Formats data and outputs to file or stdout based on options.
|
|
18
54
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/output_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAGtD,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC7B,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"output_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/output_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAGtD,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;AAE1D;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpD,MAAM,WAAW,aAAa;IAC7B,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAClC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IAC1B,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC;IACrC;;OAEG;IACH,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,EAAE,SAAS,MAAM,GAAG,SAAS,KAAG,OACvB,CAAC;AAE1D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,GAAI,KAAK,MAAM,EAAE,SAAS,OAAO,KAAG,WAUlE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAAU,CAAC,EACxC,MAAM,CAAC,EACP,YAAY,gBAAgB,CAAC,CAAC,CAAC,EAC/B,SAAS,aAAa,KACpB,OAAO,CAAC,IAAI,CA6Bd,CAAC"}
|
package/dist/output_helpers.js
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
/**
|
|
3
|
+
* Whether a task's stdout carries a machine-readable document: a `json` or
|
|
4
|
+
* `markdown` report not sent to `--outfile`.
|
|
5
|
+
*
|
|
6
|
+
* @param format - the task's `--format`
|
|
7
|
+
* @param outfile - the task's `--outfile`, if any
|
|
8
|
+
*/
|
|
9
|
+
export const output_is_machine = (format, outfile) => (format === 'json' || format === 'markdown') && !outfile;
|
|
10
|
+
/**
|
|
11
|
+
* Keeps a task's stdout for its machine-readable document or stream when
|
|
12
|
+
* `machine` is set: the logger's `info` and `debug` lines, which it writes with
|
|
13
|
+
* `console.log`, go where its errors go — stderr — and child loggers inherit
|
|
14
|
+
* that. Gro hands a task the logger its own lines go through, so gro's lines
|
|
15
|
+
* after the task runs (`✓`, the timings) follow to stderr; the two it prints
|
|
16
|
+
* before the task runs (`invoking`, `→ <task>`) stay on stdout, out of the
|
|
17
|
+
* task's reach.
|
|
18
|
+
*
|
|
19
|
+
* @param log - the task's logger
|
|
20
|
+
* @param machine - whether stdout carries a machine-readable document or stream
|
|
21
|
+
* @returns writes to the stdout the logger wrote to before, for the document
|
|
22
|
+
* @mutates log - overrides its `console` when `machine` is set
|
|
23
|
+
*/
|
|
24
|
+
export const route_human_output = (log, machine) => {
|
|
25
|
+
const stdout = log.console;
|
|
26
|
+
if (machine) {
|
|
27
|
+
log.console = {
|
|
28
|
+
log: (...args) => stdout.error(...args),
|
|
29
|
+
warn: (...args) => stdout.warn(...args),
|
|
30
|
+
error: (...args) => stdout.error(...args)
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return (content) => stdout.log(content);
|
|
34
|
+
};
|
|
2
35
|
/**
|
|
3
36
|
* Formats data and outputs to file or stdout based on options.
|
|
4
37
|
*
|
|
@@ -10,7 +43,7 @@ import { writeFile } from 'node:fs/promises';
|
|
|
10
43
|
* @throws {Error} if stdout format used with `outfile`, or if logger missing for stdout
|
|
11
44
|
*/
|
|
12
45
|
export const format_and_output = async (data, formatters, options) => {
|
|
13
|
-
const { format, outfile, log } = options;
|
|
46
|
+
const { format, outfile, log, write_stdout = write_console_log } = options;
|
|
14
47
|
// Handle stdout format (special case - uses logger directly)
|
|
15
48
|
if (format === 'stdout') {
|
|
16
49
|
if (outfile) {
|
|
@@ -34,7 +67,8 @@ export const format_and_output = async (data, formatters, options) => {
|
|
|
34
67
|
// line with `[taskname]`, corrupting JSON and cluttering markdown — keep the
|
|
35
68
|
// machine-readable formats unprefixed and pipeable (use `--outfile` for output
|
|
36
69
|
// fully free of Gro's own preamble).
|
|
37
|
-
|
|
38
|
-
console.log(content);
|
|
70
|
+
write_stdout(content);
|
|
39
71
|
}
|
|
40
72
|
};
|
|
73
|
+
// eslint-disable-next-line no-console
|
|
74
|
+
const write_console_log = (content) => console.log(content);
|
|
@@ -1,47 +1,40 @@
|
|
|
1
1
|
import type { Logger } from '@fuzdev/fuz_util/log.ts';
|
|
2
2
|
import type { LocalRepo } from './local_repo.js';
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
skip_changesets?: boolean;
|
|
6
|
-
skip_build_validation?: boolean;
|
|
7
|
-
required_branch?: string;
|
|
8
|
-
check_remote?: boolean;
|
|
9
|
-
estimate_time?: boolean;
|
|
10
|
-
log?: Logger;
|
|
11
|
-
}
|
|
3
|
+
import type { VersionChange } from './publishing_plan.js';
|
|
4
|
+
import type { NpmOperations, BuildOperations } from './operations.js';
|
|
12
5
|
export interface PreflightResult {
|
|
13
6
|
ok: boolean;
|
|
14
7
|
warnings: Array<string>;
|
|
15
8
|
errors: Array<string>;
|
|
16
|
-
repos_with_changesets: Set<string>;
|
|
17
|
-
repos_without_changesets: Set<string>;
|
|
18
|
-
estimated_duration?: number;
|
|
19
|
-
npm_username?: string;
|
|
20
9
|
}
|
|
21
10
|
export interface RunPreflightChecksOptions {
|
|
22
11
|
repos: Array<LocalRepo>;
|
|
23
|
-
|
|
24
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The plan's version changes — every package the run publishes, explicit,
|
|
14
|
+
* escalated, and auto-generated alike. Preflight builds exactly these.
|
|
15
|
+
*/
|
|
16
|
+
version_changes: Array<VersionChange>;
|
|
17
|
+
log?: Logger;
|
|
25
18
|
npm_ops?: NpmOperations;
|
|
26
19
|
build_ops?: BuildOperations;
|
|
27
|
-
changeset_ops?: ChangesetOperations;
|
|
28
20
|
}
|
|
29
21
|
/**
|
|
30
|
-
* Validates
|
|
22
|
+
* Validates the publish-time requirements beyond repo git state:
|
|
23
|
+
* - every package the plan publishes builds (fail-fast to prevent broken state)
|
|
24
|
+
* - npm authentication
|
|
25
|
+
* - npm registry connectivity
|
|
31
26
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* - NPM authentication with username
|
|
39
|
-
* - NPM registry connectivity
|
|
27
|
+
* What publishes is the plan's to decide, so preflight reads no changesets: it
|
|
28
|
+
* builds each package in `version_changes`. Git state — each repo on its
|
|
29
|
+
* registry branch, clean, idle, in sync with origin or ahead of it, and no live
|
|
30
|
+
* session in its checkout — is the readiness gate's, which `gitops_publish
|
|
31
|
+
* --wetrun` runs before the plan's confirmation prompt (`repo_readiness.ts`), so
|
|
32
|
+
* preflight reads no git.
|
|
40
33
|
*
|
|
41
34
|
* Build validation runs BEFORE any publishing to prevent the scenario where
|
|
42
35
|
* version is bumped but build fails, leaving repo in broken state.
|
|
43
36
|
*
|
|
44
|
-
* @returns result with `ok`=false if any errors, plus warnings
|
|
37
|
+
* @returns result with `ok`=false if any errors, plus warnings
|
|
45
38
|
*/
|
|
46
|
-
export declare const run_preflight_checks: ({ repos,
|
|
39
|
+
export declare const run_preflight_checks: ({ repos, version_changes, log, npm_ops, build_ops }: RunPreflightChecksOptions) => Promise<PreflightResult>;
|
|
47
40
|
//# sourceMappingURL=preflight_checks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preflight_checks.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/preflight_checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"preflight_checks.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/preflight_checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAGtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGtE,MAAM,WAAW,eAAe;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACtB;AAED,MAAM,WAAW,yBAAyB;IACzC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACxB;;;OAGG;IACH,eAAe,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,oBAAoB,GAAU,qDAMxC,yBAAyB,KAAG,OAAO,CAAC,eAAe,CAkFrD,CAAC"}
|