@fuzdev/fuz_gitops 0.57.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/LICENSE +21 -0
- package/README.md +119 -0
- package/dist/ModulesDetail.svelte +180 -0
- package/dist/ModulesDetail.svelte.d.ts +10 -0
- package/dist/ModulesDetail.svelte.d.ts.map +1 -0
- package/dist/ModulesNav.svelte +43 -0
- package/dist/ModulesNav.svelte.d.ts +11 -0
- package/dist/ModulesNav.svelte.d.ts.map +1 -0
- package/dist/ModulesPage.svelte +50 -0
- package/dist/ModulesPage.svelte.d.ts +9 -0
- package/dist/ModulesPage.svelte.d.ts.map +1 -0
- package/dist/PageFooter.svelte +15 -0
- package/dist/PageFooter.svelte.d.ts +19 -0
- package/dist/PageFooter.svelte.d.ts.map +1 -0
- package/dist/PageHeader.svelte +35 -0
- package/dist/PageHeader.svelte.d.ts +19 -0
- package/dist/PageHeader.svelte.d.ts.map +1 -0
- package/dist/PullRequestsDetail.svelte +53 -0
- package/dist/PullRequestsDetail.svelte.d.ts +10 -0
- package/dist/PullRequestsDetail.svelte.d.ts.map +1 -0
- package/dist/PullRequestsPage.svelte +47 -0
- package/dist/PullRequestsPage.svelte.d.ts +11 -0
- package/dist/PullRequestsPage.svelte.d.ts.map +1 -0
- package/dist/ReposTable.svelte +189 -0
- package/dist/ReposTable.svelte.d.ts +9 -0
- package/dist/ReposTable.svelte.d.ts.map +1 -0
- package/dist/ReposTree.svelte +88 -0
- package/dist/ReposTree.svelte.d.ts +11 -0
- package/dist/ReposTree.svelte.d.ts.map +1 -0
- package/dist/ReposTreeNav.svelte +55 -0
- package/dist/ReposTreeNav.svelte.d.ts +11 -0
- package/dist/ReposTreeNav.svelte.d.ts.map +1 -0
- package/dist/TablePage.svelte +46 -0
- package/dist/TablePage.svelte.d.ts +9 -0
- package/dist/TablePage.svelte.d.ts.map +1 -0
- package/dist/TreeItemPage.svelte +75 -0
- package/dist/TreeItemPage.svelte.d.ts +10 -0
- package/dist/TreeItemPage.svelte.d.ts.map +1 -0
- package/dist/TreePage.svelte +64 -0
- package/dist/TreePage.svelte.d.ts +9 -0
- package/dist/TreePage.svelte.d.ts.map +1 -0
- package/dist/changeset_generator.d.ts +38 -0
- package/dist/changeset_generator.d.ts.map +1 -0
- package/dist/changeset_generator.js +110 -0
- package/dist/changeset_reader.d.ts +75 -0
- package/dist/changeset_reader.d.ts.map +1 -0
- package/dist/changeset_reader.js +167 -0
- package/dist/constants.d.ts +9 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +8 -0
- package/dist/dependency_graph.d.ts +120 -0
- package/dist/dependency_graph.d.ts.map +1 -0
- package/dist/dependency_graph.js +341 -0
- package/dist/dependency_updater.d.ts +46 -0
- package/dist/dependency_updater.d.ts.map +1 -0
- package/dist/dependency_updater.js +213 -0
- package/dist/fetch_repo_data.d.ts +19 -0
- package/dist/fetch_repo_data.d.ts.map +1 -0
- package/dist/fetch_repo_data.js +49 -0
- package/dist/fs_fetch_value_cache.d.ts +24 -0
- package/dist/fs_fetch_value_cache.d.ts.map +1 -0
- package/dist/fs_fetch_value_cache.js +61 -0
- package/dist/git_operations.d.ts +54 -0
- package/dist/git_operations.d.ts.map +1 -0
- package/dist/git_operations.js +144 -0
- package/dist/github.d.ts +91 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +94 -0
- package/dist/github_helpers.d.ts +10 -0
- package/dist/github_helpers.d.ts.map +1 -0
- package/dist/github_helpers.js +13 -0
- package/dist/gitops_analyze.task.d.ts +17 -0
- package/dist/gitops_analyze.task.d.ts.map +1 -0
- package/dist/gitops_analyze.task.js +188 -0
- package/dist/gitops_config.d.ts +56 -0
- package/dist/gitops_config.d.ts.map +1 -0
- package/dist/gitops_config.js +63 -0
- package/dist/gitops_plan.task.d.ts +28 -0
- package/dist/gitops_plan.task.d.ts.map +1 -0
- package/dist/gitops_plan.task.js +217 -0
- package/dist/gitops_publish.task.d.ts +29 -0
- package/dist/gitops_publish.task.d.ts.map +1 -0
- package/dist/gitops_publish.task.js +178 -0
- package/dist/gitops_sync.task.d.ts +18 -0
- package/dist/gitops_sync.task.d.ts.map +1 -0
- package/dist/gitops_sync.task.js +95 -0
- package/dist/gitops_task_helpers.d.ts +63 -0
- package/dist/gitops_task_helpers.d.ts.map +1 -0
- package/dist/gitops_task_helpers.js +84 -0
- package/dist/gitops_validate.task.d.ts +12 -0
- package/dist/gitops_validate.task.d.ts.map +1 -0
- package/dist/gitops_validate.task.js +210 -0
- package/dist/graph_validation.d.ts +39 -0
- package/dist/graph_validation.d.ts.map +1 -0
- package/dist/graph_validation.js +79 -0
- package/dist/local_repo.d.ts +84 -0
- package/dist/local_repo.d.ts.map +1 -0
- package/dist/local_repo.js +213 -0
- package/dist/log_helpers.d.ts +43 -0
- package/dist/log_helpers.d.ts.map +1 -0
- package/dist/log_helpers.js +98 -0
- package/dist/multi_repo_publisher.d.ts +34 -0
- package/dist/multi_repo_publisher.d.ts.map +1 -0
- package/dist/multi_repo_publisher.js +364 -0
- package/dist/npm_install_helpers.d.ts +23 -0
- package/dist/npm_install_helpers.d.ts.map +1 -0
- package/dist/npm_install_helpers.js +60 -0
- package/dist/npm_registry.d.ts +46 -0
- package/dist/npm_registry.d.ts.map +1 -0
- package/dist/npm_registry.js +96 -0
- package/dist/operations.d.ts +409 -0
- package/dist/operations.d.ts.map +1 -0
- package/dist/operations.js +34 -0
- package/dist/operations_defaults.d.ts +19 -0
- package/dist/operations_defaults.d.ts.map +1 -0
- package/dist/operations_defaults.js +279 -0
- package/dist/output_helpers.d.ts +27 -0
- package/dist/output_helpers.d.ts.map +1 -0
- package/dist/output_helpers.js +39 -0
- package/dist/paths.d.ts +11 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +10 -0
- package/dist/preflight_checks.d.ts +47 -0
- package/dist/preflight_checks.d.ts.map +1 -0
- package/dist/preflight_checks.js +181 -0
- package/dist/publishing_plan.d.ts +100 -0
- package/dist/publishing_plan.d.ts.map +1 -0
- package/dist/publishing_plan.js +353 -0
- package/dist/publishing_plan_helpers.d.ts +30 -0
- package/dist/publishing_plan_helpers.d.ts.map +1 -0
- package/dist/publishing_plan_helpers.js +112 -0
- package/dist/publishing_plan_logging.d.ts +18 -0
- package/dist/publishing_plan_logging.d.ts.map +1 -0
- package/dist/publishing_plan_logging.js +342 -0
- package/dist/repo.svelte.d.ts +52 -0
- package/dist/repo.svelte.d.ts.map +1 -0
- package/dist/repo.svelte.js +70 -0
- package/dist/repo_ops.d.ts +57 -0
- package/dist/repo_ops.d.ts.map +1 -0
- package/dist/repo_ops.js +167 -0
- package/dist/resolved_gitops_config.d.ts +9 -0
- package/dist/resolved_gitops_config.d.ts.map +1 -0
- package/dist/resolved_gitops_config.js +12 -0
- package/dist/semver.d.ts +24 -0
- package/dist/semver.d.ts.map +1 -0
- package/dist/semver.js +140 -0
- package/dist/serialization_types.d.ts +57 -0
- package/dist/serialization_types.d.ts.map +1 -0
- package/dist/serialization_types.js +40 -0
- package/dist/version_utils.d.ts +48 -0
- package/dist/version_utils.d.ts.map +1 -0
- package/dist/version_utils.js +125 -0
- package/package.json +107 -0
- package/src/lib/changeset_generator.ts +162 -0
- package/src/lib/changeset_reader.ts +218 -0
- package/src/lib/constants.ts +8 -0
- package/src/lib/dependency_graph.ts +423 -0
- package/src/lib/dependency_updater.ts +297 -0
- package/src/lib/fetch_repo_data.ts +64 -0
- package/src/lib/fs_fetch_value_cache.ts +75 -0
- package/src/lib/git_operations.ts +208 -0
- package/src/lib/github.ts +128 -0
- package/src/lib/github_helpers.ts +31 -0
- package/src/lib/gitops_analyze.task.ts +261 -0
- package/src/lib/gitops_config.ts +123 -0
- package/src/lib/gitops_plan.task.ts +272 -0
- package/src/lib/gitops_publish.task.ts +227 -0
- package/src/lib/gitops_sync.task.ts +109 -0
- package/src/lib/gitops_task_helpers.ts +126 -0
- package/src/lib/gitops_validate.task.ts +248 -0
- package/src/lib/graph_validation.ts +109 -0
- package/src/lib/local_repo.ts +359 -0
- package/src/lib/log_helpers.ts +147 -0
- package/src/lib/multi_repo_publisher.ts +464 -0
- package/src/lib/npm_install_helpers.ts +85 -0
- package/src/lib/npm_registry.ts +143 -0
- package/src/lib/operations.ts +334 -0
- package/src/lib/operations_defaults.ts +335 -0
- package/src/lib/output_helpers.ts +64 -0
- package/src/lib/paths.ts +11 -0
- package/src/lib/preflight_checks.ts +269 -0
- package/src/lib/publishing_plan.ts +531 -0
- package/src/lib/publishing_plan_helpers.ts +145 -0
- package/src/lib/publishing_plan_logging.ts +470 -0
- package/src/lib/repo.svelte.ts +95 -0
- package/src/lib/repo_ops.ts +213 -0
- package/src/lib/resolved_gitops_config.ts +27 -0
- package/src/lib/semver.ts +166 -0
- package/src/lib/serialization_types.ts +90 -0
- package/src/lib/version_utils.ts +150 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production implementations of operations interfaces.
|
|
3
|
+
*
|
|
4
|
+
* Provides real git, npm, fs, and build operations for production use.
|
|
5
|
+
* For interface definitions and dependency injection pattern, see `operations.ts`.
|
|
6
|
+
*/
|
|
7
|
+
import { spawn, spawn_out } from '@fuzdev/fuz_util/process.js';
|
|
8
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
9
|
+
import { git_checkout } from '@fuzdev/fuz_util/git.js';
|
|
10
|
+
import { EMPTY_OBJECT } from '@fuzdev/fuz_util/object.js';
|
|
11
|
+
import { has_changesets, read_changesets, predict_next_version } from './changeset_reader.js';
|
|
12
|
+
import { wait_for_package, check_package_available } from './npm_registry.js';
|
|
13
|
+
import { run_preflight_checks } from './preflight_checks.js';
|
|
14
|
+
import { git_add, git_commit, git_add_and_commit, git_tag, git_push_tag, git_has_changes, git_get_changed_files, git_has_file_changed, git_stash, git_stash_pop, git_switch_branch, git_current_branch_name_required, git_current_commit_hash_required, git_check_clean_workspace_as_boolean, git_has_remote, } from './git_operations.js';
|
|
15
|
+
/** Wrap an async function that returns a value */
|
|
16
|
+
const wrap_with_value = async (fn) => {
|
|
17
|
+
try {
|
|
18
|
+
const value = await fn();
|
|
19
|
+
return { ok: true, value };
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return { ok: false, message: String(error) };
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/** Wrap an async function, ignoring its return value */
|
|
26
|
+
const wrap_void = async (fn) => {
|
|
27
|
+
try {
|
|
28
|
+
await fn();
|
|
29
|
+
return { ok: true };
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return { ok: false, message: String(error) };
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
export const default_changeset_operations = {
|
|
36
|
+
has_changesets: async (options) => {
|
|
37
|
+
const { repo } = options;
|
|
38
|
+
return wrap_with_value(() => has_changesets(repo));
|
|
39
|
+
},
|
|
40
|
+
read_changesets: async (options) => {
|
|
41
|
+
const { repo, log } = options;
|
|
42
|
+
return wrap_with_value(() => read_changesets(repo, log));
|
|
43
|
+
},
|
|
44
|
+
predict_next_version: async (options) => {
|
|
45
|
+
const { repo, log } = options;
|
|
46
|
+
try {
|
|
47
|
+
const result = await predict_next_version(repo, log);
|
|
48
|
+
if (result === null) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
return { ok: true, ...result };
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
return { ok: false, message: String(error) };
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
export const default_git_operations = {
|
|
59
|
+
// Core git info
|
|
60
|
+
current_branch_name: async (options) => {
|
|
61
|
+
const { cwd } = options ?? EMPTY_OBJECT;
|
|
62
|
+
return wrap_with_value(() => git_current_branch_name_required(cwd ? { cwd } : undefined));
|
|
63
|
+
},
|
|
64
|
+
current_commit_hash: async (options) => {
|
|
65
|
+
const { branch, cwd } = options ?? EMPTY_OBJECT;
|
|
66
|
+
return wrap_with_value(() => git_current_commit_hash_required(branch, cwd ? { cwd } : undefined));
|
|
67
|
+
},
|
|
68
|
+
check_clean_workspace: async (options) => {
|
|
69
|
+
const { cwd } = options ?? EMPTY_OBJECT;
|
|
70
|
+
return wrap_with_value(() => git_check_clean_workspace_as_boolean(cwd ? { cwd } : undefined));
|
|
71
|
+
},
|
|
72
|
+
// Branch operations
|
|
73
|
+
checkout: async (options) => {
|
|
74
|
+
const { branch, cwd } = options;
|
|
75
|
+
return wrap_void(() => git_checkout(branch, cwd ? { cwd } : undefined));
|
|
76
|
+
},
|
|
77
|
+
pull: async (options) => {
|
|
78
|
+
const { origin, branch, cwd } = options ?? EMPTY_OBJECT;
|
|
79
|
+
return wrap_void(() => spawn('git', ['pull', origin || 'origin', branch || ''], cwd ? { cwd } : undefined));
|
|
80
|
+
},
|
|
81
|
+
switch_branch: async (options) => {
|
|
82
|
+
const { branch, pull, cwd } = options;
|
|
83
|
+
return wrap_void(() => git_switch_branch(branch, pull, cwd ? { cwd } : undefined));
|
|
84
|
+
},
|
|
85
|
+
has_remote: async (options) => {
|
|
86
|
+
const { remote, cwd } = options ?? EMPTY_OBJECT;
|
|
87
|
+
return wrap_with_value(() => git_has_remote(remote, cwd ? { cwd } : undefined));
|
|
88
|
+
},
|
|
89
|
+
// Staging and committing
|
|
90
|
+
add: async (options) => {
|
|
91
|
+
const { files, cwd } = options;
|
|
92
|
+
return wrap_void(() => git_add(files, cwd ? { cwd } : undefined));
|
|
93
|
+
},
|
|
94
|
+
commit: async (options) => {
|
|
95
|
+
const { message, cwd } = options;
|
|
96
|
+
return wrap_void(() => git_commit(message, cwd ? { cwd } : undefined));
|
|
97
|
+
},
|
|
98
|
+
add_and_commit: async (options) => {
|
|
99
|
+
const { files, message, cwd } = options;
|
|
100
|
+
return wrap_void(() => git_add_and_commit(files, message, cwd ? { cwd } : undefined));
|
|
101
|
+
},
|
|
102
|
+
has_changes: async (options) => {
|
|
103
|
+
const { cwd } = options ?? EMPTY_OBJECT;
|
|
104
|
+
return wrap_with_value(() => git_has_changes(cwd ? { cwd } : undefined));
|
|
105
|
+
},
|
|
106
|
+
get_changed_files: async (options) => {
|
|
107
|
+
const { cwd } = options ?? EMPTY_OBJECT;
|
|
108
|
+
return wrap_with_value(() => git_get_changed_files(cwd ? { cwd } : undefined));
|
|
109
|
+
},
|
|
110
|
+
// Tagging
|
|
111
|
+
tag: async (options) => {
|
|
112
|
+
const { tag_name, message, cwd } = options;
|
|
113
|
+
return wrap_void(() => git_tag(tag_name, message, cwd ? { cwd } : undefined));
|
|
114
|
+
},
|
|
115
|
+
push_tag: async (options) => {
|
|
116
|
+
const { tag_name, origin, cwd } = options;
|
|
117
|
+
return wrap_void(() => git_push_tag(tag_name, origin, cwd ? { cwd } : undefined));
|
|
118
|
+
},
|
|
119
|
+
// Stashing
|
|
120
|
+
stash: async (options) => {
|
|
121
|
+
const { message, cwd } = options ?? EMPTY_OBJECT;
|
|
122
|
+
return wrap_void(() => git_stash(message, cwd ? { cwd } : undefined));
|
|
123
|
+
},
|
|
124
|
+
stash_pop: async (options) => {
|
|
125
|
+
const { cwd } = options ?? EMPTY_OBJECT;
|
|
126
|
+
return wrap_void(() => git_stash_pop(cwd ? { cwd } : undefined));
|
|
127
|
+
},
|
|
128
|
+
// File change detection
|
|
129
|
+
has_file_changed: async (options) => {
|
|
130
|
+
const { from_commit, to_commit, file_path, cwd } = options;
|
|
131
|
+
return wrap_with_value(() => git_has_file_changed(from_commit, to_commit, file_path, cwd ? { cwd } : undefined));
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
export const default_process_operations = {
|
|
135
|
+
spawn: async (options) => {
|
|
136
|
+
const { cmd, args, spawn_options } = options;
|
|
137
|
+
try {
|
|
138
|
+
const spawned = await spawn_out(cmd, args, spawn_options);
|
|
139
|
+
if (spawned.result.ok) {
|
|
140
|
+
return {
|
|
141
|
+
ok: true,
|
|
142
|
+
stdout: spawned.stdout || undefined,
|
|
143
|
+
stderr: spawned.stderr || undefined,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
return {
|
|
148
|
+
ok: false,
|
|
149
|
+
message: 'Command failed',
|
|
150
|
+
stderr: spawned.stderr || undefined,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
return { ok: false, message: String(error) };
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
export const default_npm_operations = {
|
|
160
|
+
wait_for_package: async (options) => {
|
|
161
|
+
const { pkg, version, wait_options, log } = options;
|
|
162
|
+
try {
|
|
163
|
+
await wait_for_package(pkg, version, { ...wait_options, log });
|
|
164
|
+
return { ok: true };
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
return { ok: false, message: String(error), timeout: true };
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
check_package_available: async (options) => {
|
|
171
|
+
const { pkg, version, log } = options;
|
|
172
|
+
return wrap_with_value(() => check_package_available(pkg, version, { log }));
|
|
173
|
+
},
|
|
174
|
+
check_auth: async () => {
|
|
175
|
+
try {
|
|
176
|
+
const result = await spawn_out('npm', ['whoami']);
|
|
177
|
+
if (result.stdout) {
|
|
178
|
+
const username = result.stdout.trim();
|
|
179
|
+
if (username) {
|
|
180
|
+
return { ok: true, username };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return { ok: false, message: 'Not logged in to npm' };
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
return { ok: false, message: String(error) };
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
check_registry: async () => {
|
|
190
|
+
try {
|
|
191
|
+
const result = await spawn_out('npm', ['ping']);
|
|
192
|
+
if (result.stdout) {
|
|
193
|
+
return { ok: true };
|
|
194
|
+
}
|
|
195
|
+
return { ok: false, message: 'Failed to ping npm registry' };
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
return { ok: false, message: String(error) };
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
install: async (options) => {
|
|
202
|
+
const { cwd } = options ?? EMPTY_OBJECT;
|
|
203
|
+
try {
|
|
204
|
+
const spawned = await spawn_out('npm', ['install'], cwd ? { cwd } : undefined);
|
|
205
|
+
if (spawned.result.ok) {
|
|
206
|
+
return { ok: true };
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
return { ok: false, message: 'Install failed', stderr: spawned.stderr || undefined };
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
return { ok: false, message: String(error) };
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
cache_clean: async () => {
|
|
217
|
+
try {
|
|
218
|
+
const spawned = await spawn_out('npm', ['cache', 'clean', '--force']);
|
|
219
|
+
if (spawned.result.ok) {
|
|
220
|
+
return { ok: true };
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
return { ok: false, message: 'Cache clean failed' };
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
return { ok: false, message: String(error) };
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
export const default_preflight_operations = {
|
|
232
|
+
run_preflight_checks: async (options) => {
|
|
233
|
+
return run_preflight_checks(options);
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
export const default_fs_operations = {
|
|
237
|
+
readFile: async (options) => {
|
|
238
|
+
const { path, encoding } = options;
|
|
239
|
+
return wrap_with_value(() => readFile(path, encoding));
|
|
240
|
+
},
|
|
241
|
+
writeFile: async (options) => {
|
|
242
|
+
const { path, content } = options;
|
|
243
|
+
return wrap_void(() => writeFile(path, content));
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
export const default_build_operations = {
|
|
247
|
+
build_package: async (options) => {
|
|
248
|
+
const { repo, log } = options;
|
|
249
|
+
try {
|
|
250
|
+
log?.info(` Building ${repo.library.name}...`);
|
|
251
|
+
const spawned = await spawn_out('gro', ['build'], { cwd: repo.repo_dir });
|
|
252
|
+
if (spawned.result.ok) {
|
|
253
|
+
return { ok: true };
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
return {
|
|
257
|
+
ok: false,
|
|
258
|
+
message: 'Build failed',
|
|
259
|
+
output: spawned.stderr || spawned.stdout || 'Build failed',
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
return { ok: false, message: String(error) };
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
/**
|
|
269
|
+
* Combined default operations for all gitops functionality.
|
|
270
|
+
*/
|
|
271
|
+
export const default_gitops_operations = {
|
|
272
|
+
changeset: default_changeset_operations,
|
|
273
|
+
git: default_git_operations,
|
|
274
|
+
process: default_process_operations,
|
|
275
|
+
npm: default_npm_operations,
|
|
276
|
+
preflight: default_preflight_operations,
|
|
277
|
+
fs: default_fs_operations,
|
|
278
|
+
build: default_build_operations,
|
|
279
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Logger } from '@fuzdev/fuz_util/log.js';
|
|
2
|
+
export type OutputFormat = 'stdout' | 'json' | 'markdown';
|
|
3
|
+
export interface OutputOptions {
|
|
4
|
+
format: OutputFormat;
|
|
5
|
+
outfile?: string;
|
|
6
|
+
log?: Logger;
|
|
7
|
+
}
|
|
8
|
+
export interface OutputFormatters<T> {
|
|
9
|
+
json: (data: T) => string;
|
|
10
|
+
markdown: (data: T) => Array<string>;
|
|
11
|
+
/**
|
|
12
|
+
* This function should call log methods directly for colored/styled output.
|
|
13
|
+
*/
|
|
14
|
+
stdout: (data: T, log: Logger) => void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Formats data and outputs to file or stdout based on options.
|
|
18
|
+
*
|
|
19
|
+
* Supports three formats:
|
|
20
|
+
* - stdout: Uses logger for colored/styled output (cannot use with --outfile)
|
|
21
|
+
* - json: Stringified JSON
|
|
22
|
+
* - markdown: Formatted markdown text
|
|
23
|
+
*
|
|
24
|
+
* @throws {Error} if stdout format used with outfile, or if logger missing for stdout
|
|
25
|
+
*/
|
|
26
|
+
export declare const format_and_output: <T>(data: T, formatters: OutputFormatters<T>, options: OutputOptions) => Promise<void>;
|
|
27
|
+
//# sourceMappingURL=output_helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/output_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAGpD,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;CACb;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;;;;;;;;;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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
/**
|
|
3
|
+
* Formats data and outputs to file or stdout based on options.
|
|
4
|
+
*
|
|
5
|
+
* Supports three formats:
|
|
6
|
+
* - stdout: Uses logger for colored/styled output (cannot use with --outfile)
|
|
7
|
+
* - json: Stringified JSON
|
|
8
|
+
* - markdown: Formatted markdown text
|
|
9
|
+
*
|
|
10
|
+
* @throws {Error} if stdout format used with outfile, or if logger missing for stdout
|
|
11
|
+
*/
|
|
12
|
+
export const format_and_output = async (data, formatters, options) => {
|
|
13
|
+
const { format, outfile, log } = options;
|
|
14
|
+
// Handle stdout format (special case - uses logger directly)
|
|
15
|
+
if (format === 'stdout') {
|
|
16
|
+
if (outfile) {
|
|
17
|
+
throw new Error('--outfile is not supported with stdout format, use json or markdown');
|
|
18
|
+
}
|
|
19
|
+
if (!log) {
|
|
20
|
+
throw new Error('Logger is required for stdout format');
|
|
21
|
+
}
|
|
22
|
+
formatters.stdout(data, log);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Format data
|
|
26
|
+
const content = format === 'json' ? formatters.json(data) : formatters.markdown(data).join('\n');
|
|
27
|
+
// Output to file or log
|
|
28
|
+
if (outfile) {
|
|
29
|
+
await writeFile(outfile, content);
|
|
30
|
+
log?.info(`Output written to ${outfile}`);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
// Log line by line for better formatting
|
|
34
|
+
const lines = content.split('\n');
|
|
35
|
+
for (const line of lines) {
|
|
36
|
+
log?.info(line);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base directory for all gitops-generated files.
|
|
3
|
+
*/
|
|
4
|
+
export declare const GITOPS_OUTPUT_DIR = ".gro/fuz_gitops";
|
|
5
|
+
/**
|
|
6
|
+
* Default repos directory relative to gitops config file.
|
|
7
|
+
* Resolves to the parent of the directory with the config
|
|
8
|
+
* (e.g., ~/dev/repo/gitops.config.ts resolves to ~/dev/).
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_REPOS_DIR = "..";
|
|
11
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/paths.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,iBAAiB,oBAAoB,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,OAAO,CAAC"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base directory for all gitops-generated files.
|
|
3
|
+
*/
|
|
4
|
+
export const GITOPS_OUTPUT_DIR = '.gro/fuz_gitops';
|
|
5
|
+
/**
|
|
6
|
+
* Default repos directory relative to gitops config file.
|
|
7
|
+
* Resolves to the parent of the directory with the config
|
|
8
|
+
* (e.g., ~/dev/repo/gitops.config.ts resolves to ~/dev/).
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_REPOS_DIR = '..';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Logger } from '@fuzdev/fuz_util/log.js';
|
|
2
|
+
import type { LocalRepo } from './local_repo.js';
|
|
3
|
+
import type { GitOperations, NpmOperations, BuildOperations, ChangesetOperations } from './operations.js';
|
|
4
|
+
export interface PreflightOptions {
|
|
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
|
+
}
|
|
12
|
+
export interface PreflightResult {
|
|
13
|
+
ok: boolean;
|
|
14
|
+
warnings: Array<string>;
|
|
15
|
+
errors: Array<string>;
|
|
16
|
+
repos_with_changesets: Set<string>;
|
|
17
|
+
repos_without_changesets: Set<string>;
|
|
18
|
+
estimated_duration?: number;
|
|
19
|
+
npm_username?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface RunPreflightChecksOptions {
|
|
22
|
+
repos: Array<LocalRepo>;
|
|
23
|
+
preflight_options?: PreflightOptions;
|
|
24
|
+
git_ops?: GitOperations;
|
|
25
|
+
npm_ops?: NpmOperations;
|
|
26
|
+
build_ops?: BuildOperations;
|
|
27
|
+
changeset_ops?: ChangesetOperations;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Validates all requirements before publishing can proceed.
|
|
31
|
+
*
|
|
32
|
+
* Performs comprehensive pre-flight validation:
|
|
33
|
+
* - Clean workspaces (100% clean required - no uncommitted changes)
|
|
34
|
+
* - Correct branch (usually main)
|
|
35
|
+
* - Changesets present (unless skip_changesets=true)
|
|
36
|
+
* - Builds successful (fail-fast to prevent broken state)
|
|
37
|
+
* - Git remote reachability
|
|
38
|
+
* - NPM authentication with username
|
|
39
|
+
* - NPM registry connectivity
|
|
40
|
+
*
|
|
41
|
+
* Build validation runs BEFORE any publishing to prevent the scenario where
|
|
42
|
+
* version is bumped but build fails, leaving repo in broken state.
|
|
43
|
+
*
|
|
44
|
+
* @returns result with ok=false if any errors, plus warnings and detailed status
|
|
45
|
+
*/
|
|
46
|
+
export declare const run_preflight_checks: ({ repos, preflight_options, git_ops, npm_ops, build_ops, changeset_ops, }: RunPreflightChecksOptions) => Promise<PreflightResult>;
|
|
47
|
+
//# sourceMappingURL=preflight_checks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight_checks.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/preflight_checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAKpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EACX,aAAa,EACb,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,MAAM,iBAAiB,CAAC;AAQzB,MAAM,WAAW,gBAAgB;IAChC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,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;IACtB,qBAAqB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,wBAAwB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,yBAAyB;IACzC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACxB,iBAAiB,CAAC,EAAE,gBAAgB,CAAC;IACrC,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,aAAa,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,oBAAoB,GAAU,2EAOxC,yBAAyB,KAAG,OAAO,CAAC,eAAe,CAwLrD,CAAC"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { spawn_out } from '@fuzdev/fuz_util/process.js';
|
|
2
|
+
import { styleText as st } from 'node:util';
|
|
3
|
+
import { default_git_operations, default_npm_operations, default_build_operations, default_changeset_operations, } from './operations_defaults.js';
|
|
4
|
+
/**
|
|
5
|
+
* Validates all requirements before publishing can proceed.
|
|
6
|
+
*
|
|
7
|
+
* Performs comprehensive pre-flight validation:
|
|
8
|
+
* - Clean workspaces (100% clean required - no uncommitted changes)
|
|
9
|
+
* - Correct branch (usually main)
|
|
10
|
+
* - Changesets present (unless skip_changesets=true)
|
|
11
|
+
* - Builds successful (fail-fast to prevent broken state)
|
|
12
|
+
* - Git remote reachability
|
|
13
|
+
* - NPM authentication with username
|
|
14
|
+
* - NPM registry connectivity
|
|
15
|
+
*
|
|
16
|
+
* Build validation runs BEFORE any publishing to prevent the scenario where
|
|
17
|
+
* version is bumped but build fails, leaving repo in broken state.
|
|
18
|
+
*
|
|
19
|
+
* @returns result with ok=false if any errors, plus warnings and detailed status
|
|
20
|
+
*/
|
|
21
|
+
export const run_preflight_checks = async ({ repos, preflight_options = {}, git_ops = default_git_operations, npm_ops = default_npm_operations, build_ops = default_build_operations, changeset_ops = default_changeset_operations, }) => {
|
|
22
|
+
const { skip_changesets = false, skip_build_validation = false, required_branch = 'main', check_remote = true, estimate_time = true, log, } = preflight_options;
|
|
23
|
+
const warnings = [];
|
|
24
|
+
const errors = [];
|
|
25
|
+
const repos_with_changesets = new Set();
|
|
26
|
+
const repos_without_changesets = new Set();
|
|
27
|
+
let npm_username;
|
|
28
|
+
let estimated_duration;
|
|
29
|
+
log?.info(st('cyan', '✅ Running preflight checks...'));
|
|
30
|
+
// 1. Check clean workspaces - must be 100% clean before publishing
|
|
31
|
+
log?.info(' Checking workspace cleanliness...');
|
|
32
|
+
for (const repo of repos) {
|
|
33
|
+
const clean_result = await git_ops.check_clean_workspace({ cwd: repo.repo_dir }); // eslint-disable-line no-await-in-loop
|
|
34
|
+
if (!clean_result.ok) {
|
|
35
|
+
errors.push(`${repo.library.name} failed workspace check: ${clean_result.message}`);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (!clean_result.value) {
|
|
39
|
+
// Get list of changed files for better error message
|
|
40
|
+
const files_result = await git_ops.get_changed_files({ cwd: repo.repo_dir }); // eslint-disable-line no-await-in-loop
|
|
41
|
+
if (files_result.ok) {
|
|
42
|
+
// No filtering - workspace must be 100% clean
|
|
43
|
+
const unexpected_files = files_result.value;
|
|
44
|
+
if (unexpected_files.length > 0) {
|
|
45
|
+
errors.push(`${repo.library.name} has uncommitted changes in: ${unexpected_files.slice(0, 3).join(', ')}${unexpected_files.length > 3 ? ` and ${unexpected_files.length - 3} more` : ''}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
errors.push(`${repo.library.name} has uncommitted changes`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// 2. Check correct branch
|
|
54
|
+
log?.info(` Checking branches (expecting ${required_branch})...`);
|
|
55
|
+
for (const repo of repos) {
|
|
56
|
+
const branch_result = await git_ops.current_branch_name({ cwd: repo.repo_dir }); // eslint-disable-line no-await-in-loop
|
|
57
|
+
if (!branch_result.ok) {
|
|
58
|
+
errors.push(`${repo.library.name} failed branch check: ${branch_result.message}`);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (branch_result.value !== required_branch) {
|
|
62
|
+
errors.push(`${repo.library.name} is on branch '${branch_result.value}', expected '${required_branch}'`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// 3. Check changesets (unless skipped)
|
|
66
|
+
if (!skip_changesets) {
|
|
67
|
+
log?.info(' Checking for changesets...');
|
|
68
|
+
for (const repo of repos) {
|
|
69
|
+
const has_result = await changeset_ops.has_changesets({ repo }); // eslint-disable-line no-await-in-loop
|
|
70
|
+
if (!has_result.ok) {
|
|
71
|
+
errors.push(`${repo.library.name} failed changeset check: ${has_result.message}`);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (has_result.value) {
|
|
75
|
+
repos_with_changesets.add(repo.library.name);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
repos_without_changesets.add(repo.library.name);
|
|
79
|
+
warnings.push(`${repo.library.name} has no changesets`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (repos_without_changesets.size > 0) {
|
|
83
|
+
log?.warn(st('yellow', ` ⚠️ ${repos_without_changesets.size} packages have no changesets`));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// 4. Validate builds for packages with changesets
|
|
87
|
+
if (!skip_build_validation && repos_with_changesets.size > 0) {
|
|
88
|
+
log?.info(st('cyan', ` Validating builds for ${repos_with_changesets.size} package(s)...`));
|
|
89
|
+
const repos_to_build = repos.filter((repo) => repos_with_changesets.has(repo.library.name));
|
|
90
|
+
for (let i = 0; i < repos_to_build.length; i++) {
|
|
91
|
+
const repo = repos_to_build[i];
|
|
92
|
+
log?.info(st('dim', ` [${i + 1}/${repos_to_build.length}] Building ${repo.library.name}...`));
|
|
93
|
+
const build_result = await build_ops.build_package({ repo, log }); // eslint-disable-line no-await-in-loop
|
|
94
|
+
if (!build_result.ok) {
|
|
95
|
+
errors.push(`${repo.library.name} failed to build: ${build_result.output || build_result.message || 'unknown error'}`);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
log?.info(st('dim', ` ✓ ${repo.library.name} built successfully`));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (errors.some((err) => err.includes('failed to build'))) {
|
|
102
|
+
log?.error(st('red', ' ❌ Build validation failed - fix build errors before publishing'));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
log?.info(st('green', ' ✓ All builds validated successfully'));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// 5. Check git remote reachability (skip in tests when check_remote is false)
|
|
109
|
+
if (check_remote && repos.length > 0) {
|
|
110
|
+
log?.info(' Checking git remote connectivity...');
|
|
111
|
+
// Only check first repo to avoid slowing down tests with multiple remote checks
|
|
112
|
+
const remote_result = await check_git_remote(repos[0].repo_dir);
|
|
113
|
+
if (!remote_result.ok) {
|
|
114
|
+
warnings.push(`git remote may not be reachable - ${remote_result.message}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// 6. Check npm authentication with username
|
|
118
|
+
log?.info(' Checking npm authentication...');
|
|
119
|
+
const npm_auth_result = await npm_ops.check_auth();
|
|
120
|
+
if (!npm_auth_result.ok) {
|
|
121
|
+
errors.push(`npm authentication failed: ${npm_auth_result.message || 'not logged in'}`);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
npm_username = npm_auth_result.username;
|
|
125
|
+
log?.info(st('dim', ` Logged in as: ${npm_username}`));
|
|
126
|
+
}
|
|
127
|
+
// 7. Check network connectivity (npm registry)
|
|
128
|
+
log?.info(' Checking npm registry connectivity...');
|
|
129
|
+
const registry_result = await npm_ops.check_registry();
|
|
130
|
+
if (!registry_result.ok) {
|
|
131
|
+
warnings.push(`npm registry check failed: ${registry_result.message}`);
|
|
132
|
+
}
|
|
133
|
+
// 8. Estimate total publish time
|
|
134
|
+
if (estimate_time) {
|
|
135
|
+
const packages_to_publish = repos_with_changesets.size;
|
|
136
|
+
if (packages_to_publish > 0) {
|
|
137
|
+
// Rough estimate: 30s per package + 10s per package for NPM propagation
|
|
138
|
+
estimated_duration = packages_to_publish * 40;
|
|
139
|
+
log?.info(st('dim', ` Estimated publish time: ~${Math.ceil(estimated_duration / 60)} minutes for ${packages_to_publish} package(s)`));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// Report results
|
|
143
|
+
const ok = errors.length === 0;
|
|
144
|
+
if (errors.length > 0) {
|
|
145
|
+
log?.error(st('red', `\n❌ Preflight checks failed with ${errors.length} errors:`));
|
|
146
|
+
for (const error of errors) {
|
|
147
|
+
log?.error(` - ${error}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (warnings.length > 0) {
|
|
151
|
+
log?.warn(st('yellow', `\n⚠️ Preflight checks found ${warnings.length} warnings:`));
|
|
152
|
+
for (const warning of warnings) {
|
|
153
|
+
log?.warn(` - ${warning}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (ok) {
|
|
157
|
+
log?.info(st('green', '\n✨ All preflight checks passed!'));
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
ok,
|
|
161
|
+
warnings,
|
|
162
|
+
errors,
|
|
163
|
+
repos_with_changesets,
|
|
164
|
+
repos_without_changesets,
|
|
165
|
+
estimated_duration,
|
|
166
|
+
npm_username,
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
const check_git_remote = async (cwd) => {
|
|
170
|
+
try {
|
|
171
|
+
// Try to fetch refs from remote without downloading objects
|
|
172
|
+
const result = await spawn_out('git', ['ls-remote', '--heads', 'origin'], { cwd });
|
|
173
|
+
if (result.stdout || result.stderr) {
|
|
174
|
+
return { ok: true };
|
|
175
|
+
}
|
|
176
|
+
return { ok: false, message: 'No response from git remote' };
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
return { ok: false, message: String(error) };
|
|
180
|
+
}
|
|
181
|
+
};
|