@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,64 @@
|
|
|
1
|
+
import type {Logger} from '@fuzdev/fuz_util/log.js';
|
|
2
|
+
import {writeFile} from 'node:fs/promises';
|
|
3
|
+
|
|
4
|
+
export type OutputFormat = 'stdout' | 'json' | 'markdown';
|
|
5
|
+
|
|
6
|
+
export interface OutputOptions {
|
|
7
|
+
format: OutputFormat;
|
|
8
|
+
outfile?: string;
|
|
9
|
+
log?: Logger;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface OutputFormatters<T> {
|
|
13
|
+
json: (data: T) => string;
|
|
14
|
+
markdown: (data: T) => Array<string>;
|
|
15
|
+
/**
|
|
16
|
+
* This function should call log methods directly for colored/styled output.
|
|
17
|
+
*/
|
|
18
|
+
stdout: (data: T, log: Logger) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Formats data and outputs to file or stdout based on options.
|
|
23
|
+
*
|
|
24
|
+
* Supports three formats:
|
|
25
|
+
* - stdout: Uses logger for colored/styled output (cannot use with --outfile)
|
|
26
|
+
* - json: Stringified JSON
|
|
27
|
+
* - markdown: Formatted markdown text
|
|
28
|
+
*
|
|
29
|
+
* @throws {Error} if stdout format used with outfile, or if logger missing for stdout
|
|
30
|
+
*/
|
|
31
|
+
export const format_and_output = async <T>(
|
|
32
|
+
data: T,
|
|
33
|
+
formatters: OutputFormatters<T>,
|
|
34
|
+
options: OutputOptions,
|
|
35
|
+
): Promise<void> => {
|
|
36
|
+
const {format, outfile, log} = options;
|
|
37
|
+
|
|
38
|
+
// Handle stdout format (special case - uses logger directly)
|
|
39
|
+
if (format === 'stdout') {
|
|
40
|
+
if (outfile) {
|
|
41
|
+
throw new Error('--outfile is not supported with stdout format, use json or markdown');
|
|
42
|
+
}
|
|
43
|
+
if (!log) {
|
|
44
|
+
throw new Error('Logger is required for stdout format');
|
|
45
|
+
}
|
|
46
|
+
formatters.stdout(data, log);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Format data
|
|
51
|
+
const content = format === 'json' ? formatters.json(data) : formatters.markdown(data).join('\n');
|
|
52
|
+
|
|
53
|
+
// Output to file or log
|
|
54
|
+
if (outfile) {
|
|
55
|
+
await writeFile(outfile, content);
|
|
56
|
+
log?.info(`Output written to ${outfile}`);
|
|
57
|
+
} else {
|
|
58
|
+
// Log line by line for better formatting
|
|
59
|
+
const lines = content.split('\n');
|
|
60
|
+
for (const line of lines) {
|
|
61
|
+
log?.info(line);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
package/src/lib/paths.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base directory for all gitops-generated files.
|
|
3
|
+
*/
|
|
4
|
+
export const GITOPS_OUTPUT_DIR = '.gro/fuz_gitops';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Default repos directory relative to gitops config file.
|
|
8
|
+
* Resolves to the parent of the directory with the config
|
|
9
|
+
* (e.g., ~/dev/repo/gitops.config.ts resolves to ~/dev/).
|
|
10
|
+
*/
|
|
11
|
+
export const DEFAULT_REPOS_DIR = '..';
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import type {Logger} from '@fuzdev/fuz_util/log.js';
|
|
2
|
+
import type {Result} from '@fuzdev/fuz_util/result.js';
|
|
3
|
+
import {spawn_out} from '@fuzdev/fuz_util/process.js';
|
|
4
|
+
import {styleText as st} from 'node:util';
|
|
5
|
+
|
|
6
|
+
import type {LocalRepo} from './local_repo.js';
|
|
7
|
+
import type {
|
|
8
|
+
GitOperations,
|
|
9
|
+
NpmOperations,
|
|
10
|
+
BuildOperations,
|
|
11
|
+
ChangesetOperations,
|
|
12
|
+
} from './operations.js';
|
|
13
|
+
import {
|
|
14
|
+
default_git_operations,
|
|
15
|
+
default_npm_operations,
|
|
16
|
+
default_build_operations,
|
|
17
|
+
default_changeset_operations,
|
|
18
|
+
} from './operations_defaults.js';
|
|
19
|
+
|
|
20
|
+
export interface PreflightOptions {
|
|
21
|
+
skip_changesets?: boolean;
|
|
22
|
+
skip_build_validation?: boolean; // Skip build validation (useful for tests)
|
|
23
|
+
required_branch?: string;
|
|
24
|
+
check_remote?: boolean; // Check if git remote is reachable
|
|
25
|
+
estimate_time?: boolean; // Estimate total publish time
|
|
26
|
+
log?: Logger;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface PreflightResult {
|
|
30
|
+
ok: boolean;
|
|
31
|
+
warnings: Array<string>;
|
|
32
|
+
errors: Array<string>;
|
|
33
|
+
repos_with_changesets: Set<string>;
|
|
34
|
+
repos_without_changesets: Set<string>;
|
|
35
|
+
estimated_duration?: number; // In seconds
|
|
36
|
+
npm_username?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface RunPreflightChecksOptions {
|
|
40
|
+
repos: Array<LocalRepo>;
|
|
41
|
+
preflight_options?: PreflightOptions;
|
|
42
|
+
git_ops?: GitOperations;
|
|
43
|
+
npm_ops?: NpmOperations;
|
|
44
|
+
build_ops?: BuildOperations;
|
|
45
|
+
changeset_ops?: ChangesetOperations;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Validates all requirements before publishing can proceed.
|
|
50
|
+
*
|
|
51
|
+
* Performs comprehensive pre-flight validation:
|
|
52
|
+
* - Clean workspaces (100% clean required - no uncommitted changes)
|
|
53
|
+
* - Correct branch (usually main)
|
|
54
|
+
* - Changesets present (unless skip_changesets=true)
|
|
55
|
+
* - Builds successful (fail-fast to prevent broken state)
|
|
56
|
+
* - Git remote reachability
|
|
57
|
+
* - NPM authentication with username
|
|
58
|
+
* - NPM registry connectivity
|
|
59
|
+
*
|
|
60
|
+
* Build validation runs BEFORE any publishing to prevent the scenario where
|
|
61
|
+
* version is bumped but build fails, leaving repo in broken state.
|
|
62
|
+
*
|
|
63
|
+
* @returns result with ok=false if any errors, plus warnings and detailed status
|
|
64
|
+
*/
|
|
65
|
+
export const run_preflight_checks = async ({
|
|
66
|
+
repos,
|
|
67
|
+
preflight_options = {},
|
|
68
|
+
git_ops = default_git_operations,
|
|
69
|
+
npm_ops = default_npm_operations,
|
|
70
|
+
build_ops = default_build_operations,
|
|
71
|
+
changeset_ops = default_changeset_operations,
|
|
72
|
+
}: RunPreflightChecksOptions): Promise<PreflightResult> => {
|
|
73
|
+
const {
|
|
74
|
+
skip_changesets = false,
|
|
75
|
+
skip_build_validation = false,
|
|
76
|
+
required_branch = 'main',
|
|
77
|
+
check_remote = true,
|
|
78
|
+
estimate_time = true,
|
|
79
|
+
log,
|
|
80
|
+
} = preflight_options;
|
|
81
|
+
|
|
82
|
+
const warnings: Array<string> = [];
|
|
83
|
+
const errors: Array<string> = [];
|
|
84
|
+
const repos_with_changesets: Set<string> = new Set();
|
|
85
|
+
const repos_without_changesets: Set<string> = new Set();
|
|
86
|
+
let npm_username: string | undefined;
|
|
87
|
+
let estimated_duration: number | undefined;
|
|
88
|
+
|
|
89
|
+
log?.info(st('cyan', '✅ Running preflight checks...'));
|
|
90
|
+
|
|
91
|
+
// 1. Check clean workspaces - must be 100% clean before publishing
|
|
92
|
+
log?.info(' Checking workspace cleanliness...');
|
|
93
|
+
for (const repo of repos) {
|
|
94
|
+
const clean_result = await git_ops.check_clean_workspace({cwd: repo.repo_dir}); // eslint-disable-line no-await-in-loop
|
|
95
|
+
if (!clean_result.ok) {
|
|
96
|
+
errors.push(`${repo.library.name} failed workspace check: ${clean_result.message}`);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!clean_result.value) {
|
|
101
|
+
// Get list of changed files for better error message
|
|
102
|
+
const files_result = await git_ops.get_changed_files({cwd: repo.repo_dir}); // eslint-disable-line no-await-in-loop
|
|
103
|
+
if (files_result.ok) {
|
|
104
|
+
// No filtering - workspace must be 100% clean
|
|
105
|
+
const unexpected_files = files_result.value;
|
|
106
|
+
|
|
107
|
+
if (unexpected_files.length > 0) {
|
|
108
|
+
errors.push(
|
|
109
|
+
`${repo.library.name} has uncommitted changes in: ${unexpected_files.slice(0, 3).join(', ')}${unexpected_files.length > 3 ? ` and ${unexpected_files.length - 3} more` : ''}`,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
errors.push(`${repo.library.name} has uncommitted changes`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 2. Check correct branch
|
|
119
|
+
log?.info(` Checking branches (expecting ${required_branch})...`);
|
|
120
|
+
for (const repo of repos) {
|
|
121
|
+
const branch_result = await git_ops.current_branch_name({cwd: repo.repo_dir}); // eslint-disable-line no-await-in-loop
|
|
122
|
+
if (!branch_result.ok) {
|
|
123
|
+
errors.push(`${repo.library.name} failed branch check: ${branch_result.message}`);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (branch_result.value !== required_branch) {
|
|
128
|
+
errors.push(
|
|
129
|
+
`${repo.library.name} is on branch '${branch_result.value}', expected '${required_branch}'`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 3. Check changesets (unless skipped)
|
|
135
|
+
if (!skip_changesets) {
|
|
136
|
+
log?.info(' Checking for changesets...');
|
|
137
|
+
for (const repo of repos) {
|
|
138
|
+
const has_result = await changeset_ops.has_changesets({repo}); // eslint-disable-line no-await-in-loop
|
|
139
|
+
if (!has_result.ok) {
|
|
140
|
+
errors.push(`${repo.library.name} failed changeset check: ${has_result.message}`);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (has_result.value) {
|
|
145
|
+
repos_with_changesets.add(repo.library.name);
|
|
146
|
+
} else {
|
|
147
|
+
repos_without_changesets.add(repo.library.name);
|
|
148
|
+
warnings.push(`${repo.library.name} has no changesets`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (repos_without_changesets.size > 0) {
|
|
153
|
+
log?.warn(st('yellow', ` ⚠️ ${repos_without_changesets.size} packages have no changesets`));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// 4. Validate builds for packages with changesets
|
|
158
|
+
if (!skip_build_validation && repos_with_changesets.size > 0) {
|
|
159
|
+
log?.info(st('cyan', ` Validating builds for ${repos_with_changesets.size} package(s)...`));
|
|
160
|
+
const repos_to_build = repos.filter((repo) => repos_with_changesets.has(repo.library.name));
|
|
161
|
+
|
|
162
|
+
for (let i = 0; i < repos_to_build.length; i++) {
|
|
163
|
+
const repo = repos_to_build[i]!;
|
|
164
|
+
log?.info(
|
|
165
|
+
st('dim', ` [${i + 1}/${repos_to_build.length}] Building ${repo.library.name}...`),
|
|
166
|
+
);
|
|
167
|
+
const build_result = await build_ops.build_package({repo, log}); // eslint-disable-line no-await-in-loop
|
|
168
|
+
if (!build_result.ok) {
|
|
169
|
+
errors.push(
|
|
170
|
+
`${repo.library.name} failed to build: ${build_result.output || build_result.message || 'unknown error'}`,
|
|
171
|
+
);
|
|
172
|
+
} else {
|
|
173
|
+
log?.info(st('dim', ` ✓ ${repo.library.name} built successfully`));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (errors.some((err) => err.includes('failed to build'))) {
|
|
178
|
+
log?.error(st('red', ' ❌ Build validation failed - fix build errors before publishing'));
|
|
179
|
+
} else {
|
|
180
|
+
log?.info(st('green', ' ✓ All builds validated successfully'));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// 5. Check git remote reachability (skip in tests when check_remote is false)
|
|
185
|
+
if (check_remote && repos.length > 0) {
|
|
186
|
+
log?.info(' Checking git remote connectivity...');
|
|
187
|
+
// Only check first repo to avoid slowing down tests with multiple remote checks
|
|
188
|
+
const remote_result = await check_git_remote(repos[0]!.repo_dir);
|
|
189
|
+
if (!remote_result.ok) {
|
|
190
|
+
warnings.push(`git remote may not be reachable - ${remote_result.message}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// 6. Check npm authentication with username
|
|
195
|
+
log?.info(' Checking npm authentication...');
|
|
196
|
+
const npm_auth_result = await npm_ops.check_auth();
|
|
197
|
+
if (!npm_auth_result.ok) {
|
|
198
|
+
errors.push(`npm authentication failed: ${npm_auth_result.message || 'not logged in'}`);
|
|
199
|
+
} else {
|
|
200
|
+
npm_username = npm_auth_result.username;
|
|
201
|
+
log?.info(st('dim', ` Logged in as: ${npm_username}`));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// 7. Check network connectivity (npm registry)
|
|
205
|
+
log?.info(' Checking npm registry connectivity...');
|
|
206
|
+
const registry_result = await npm_ops.check_registry();
|
|
207
|
+
if (!registry_result.ok) {
|
|
208
|
+
warnings.push(`npm registry check failed: ${registry_result.message}`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// 8. Estimate total publish time
|
|
212
|
+
if (estimate_time) {
|
|
213
|
+
const packages_to_publish = repos_with_changesets.size;
|
|
214
|
+
if (packages_to_publish > 0) {
|
|
215
|
+
// Rough estimate: 30s per package + 10s per package for NPM propagation
|
|
216
|
+
estimated_duration = packages_to_publish * 40;
|
|
217
|
+
log?.info(
|
|
218
|
+
st(
|
|
219
|
+
'dim',
|
|
220
|
+
` Estimated publish time: ~${Math.ceil(estimated_duration / 60)} minutes for ${packages_to_publish} package(s)`,
|
|
221
|
+
),
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Report results
|
|
227
|
+
const ok = errors.length === 0;
|
|
228
|
+
|
|
229
|
+
if (errors.length > 0) {
|
|
230
|
+
log?.error(st('red', `\n❌ Preflight checks failed with ${errors.length} errors:`));
|
|
231
|
+
for (const error of errors) {
|
|
232
|
+
log?.error(` - ${error}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (warnings.length > 0) {
|
|
237
|
+
log?.warn(st('yellow', `\n⚠️ Preflight checks found ${warnings.length} warnings:`));
|
|
238
|
+
for (const warning of warnings) {
|
|
239
|
+
log?.warn(` - ${warning}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (ok) {
|
|
244
|
+
log?.info(st('green', '\n✨ All preflight checks passed!'));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
ok,
|
|
249
|
+
warnings,
|
|
250
|
+
errors,
|
|
251
|
+
repos_with_changesets,
|
|
252
|
+
repos_without_changesets,
|
|
253
|
+
estimated_duration,
|
|
254
|
+
npm_username,
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const check_git_remote = async (cwd: string): Promise<Result<object, {message: string}>> => {
|
|
259
|
+
try {
|
|
260
|
+
// Try to fetch refs from remote without downloading objects
|
|
261
|
+
const result = await spawn_out('git', ['ls-remote', '--heads', 'origin'], {cwd});
|
|
262
|
+
if (result.stdout || result.stderr) {
|
|
263
|
+
return {ok: true};
|
|
264
|
+
}
|
|
265
|
+
return {ok: false, message: 'No response from git remote'};
|
|
266
|
+
} catch (error) {
|
|
267
|
+
return {ok: false, message: String(error)};
|
|
268
|
+
}
|
|
269
|
+
};
|