@monster-orange/den 0.0.0-stage → 0.1.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/CHANGELOG.md +67 -0
- package/LICENSE +21 -0
- package/README.md +166 -2
- package/bin/den +61 -0
- package/docs/distributions.md +256 -0
- package/make/demo.mk +82 -0
- package/make/den.mk +80 -0
- package/make/journeys.mk +57 -0
- package/make/local_dev.mk +154 -0
- package/make/security.mk +59 -0
- package/make/test.mk +405 -0
- package/package.json +104 -4
- package/scripts/auth-configure.ts +415 -0
- package/scripts/heal-config.ts +92 -0
- package/scripts/jsonl-playwright-reporter.js +70 -0
- package/scripts/manifest-read.cjs +91 -0
- package/scripts/setup-1password.ts +570 -0
- package/scripts/setup-secrets.ts +149 -0
- package/scripts/view-results.js +156 -0
- package/service/install.sh +112 -0
- package/src/pillars/api/fixtures/index.ts +128 -0
- package/src/pillars/api/fixtures/openapi-validator.ts +111 -0
- package/src/pillars/api/global-setup.ts +103 -0
- package/src/pillars/api/playwright.config.ts +105 -0
- package/src/pillars/api/schemas/example-api.json +110 -0
- package/src/pillars/api/tests/health/health.spec.ts +19 -0
- package/src/pillars/api/tests/health/manifest.yml +6 -0
- package/src/pillars/browser/fixtures/index.ts +232 -0
- package/src/pillars/browser/fixtures/package.json +10 -0
- package/src/pillars/browser/global-setup.ts +140 -0
- package/src/pillars/browser/global-teardown.ts +48 -0
- package/src/pillars/browser/playwright.config.ts +212 -0
- package/src/pillars/browser/setup.ts +219 -0
- package/src/pillars/journeys/app-config.ts +237 -0
- package/src/pillars/journeys/discover.ts +160 -0
- package/src/pillars/journeys/hooks/deny-shell.cjs +44 -0
- package/src/pillars/journeys/observability/events.ts +288 -0
- package/src/pillars/journeys/observability/sdk-mapper.ts +306 -0
- package/src/pillars/journeys/report/friction.ts +304 -0
- package/src/pillars/journeys/report/junit.ts +105 -0
- package/src/pillars/journeys/report/render.ts +273 -0
- package/src/pillars/journeys/report/results.ts +323 -0
- package/src/pillars/journeys/run.ts +673 -0
- package/src/pillars/journeys/runner.ts +1025 -0
- package/src/pillars/journeys/sandbox.ts +406 -0
- package/src/pillars/journeys/spec/loader.ts +152 -0
- package/src/pillars/journeys/spec/schema.ts +208 -0
- package/src/pillars/journeys/teardown.ts +98 -0
- package/src/pillars/journeys/tools/browser-session.ts +219 -0
- package/src/pillars/journeys/tools/browser-tool.ts +914 -0
- package/src/pillars/journeys/tools/http-tool.ts +564 -0
- package/src/pillars/journeys/tools/ledger.ts +278 -0
- package/src/pillars/journeys/tools/snapshot-store.ts +117 -0
- package/src/pillars/journeys/verify/assertions.ts +502 -0
- package/src/pillars/journeys/verify/verdict.ts +71 -0
- package/src/pillars/perf/build-report.ts +36 -0
- package/src/pillars/perf/k6.config.js +112 -0
- package/src/pillars/perf/run.ts +345 -0
- package/src/pillars/perf/scenarios/load-profile.js +97 -0
- package/src/pillars/perf/staging.ts +73 -0
- package/src/pillars/security/discover.ts +108 -0
- package/src/pillars/security/findings.ts +151 -0
- package/src/pillars/security/plan.ts +355 -0
- package/src/pillars/security/run.ts +729 -0
- package/src/pillars/smoke/admin-probe.ts +68 -0
- package/src/pillars/smoke/base-url.ts +56 -0
- package/src/pillars/smoke/cleanup.ts +8 -0
- package/src/pillars/smoke/discover.ts +237 -0
- package/src/pillars/smoke/ensure-smoke-teardown.ts +40 -0
- package/src/pillars/smoke/fixture-manager.ts +217 -0
- package/src/pillars/smoke/fixtures.ts +468 -0
- package/src/pillars/smoke/global-setup-all.ts +262 -0
- package/src/pillars/smoke/global-setup-global.ts +262 -0
- package/src/pillars/smoke/global-setup.ts +273 -0
- package/src/pillars/smoke/global-teardown-all.ts +8 -0
- package/src/pillars/smoke/global-teardown-global.ts +8 -0
- package/src/pillars/smoke/global-teardown.ts +139 -0
- package/src/pillars/smoke/playwright-all.config.ts +147 -0
- package/src/pillars/smoke/playwright-global.config.ts +141 -0
- package/src/pillars/smoke/playwright.config.ts +162 -0
- package/src/pillars/smoke/setup-env.ts +132 -0
- package/src/pillars/smoke/setup-global.ts +126 -0
- package/src/pillars/smoke/setup.ts +115 -0
- package/src/pillars/smoke/smoke-repo.ts +16 -0
- package/src/pillars/smoke/staging.ts +49 -0
- package/src/pillars/suites/run.ts +147 -0
- package/src/scripts/configure-aws-profiles.ts +114 -0
- package/src/scripts/register-repos.ts +307 -0
- package/src/scripts/setup-default-workspace.ts +203 -0
- package/src/shared/applications.ts +138 -0
- package/src/shared/auth/api-token.ts +416 -0
- package/src/shared/auth/auth0-helper.ts +284 -0
- package/src/shared/auth/headless-login.ts +265 -0
- package/src/shared/auth/jwt-helper.ts +186 -0
- package/src/shared/auth/sudo-vault.ts +69 -0
- package/src/shared/auth/test-accounts.ts +98 -0
- package/src/shared/auth/token-injection.ts +184 -0
- package/src/shared/auth/token-providers/auth0.ts +80 -0
- package/src/shared/auth/token-providers/index.ts +182 -0
- package/src/shared/auth/token-refresh.ts +273 -0
- package/src/shared/banner.ts +15 -0
- package/src/shared/brand.ts +79 -0
- package/src/shared/cli-tabs.ts +131 -0
- package/src/shared/constants.ts +128 -0
- package/src/shared/den-config.ts +566 -0
- package/src/shared/dev-metrics/emit.ts +354 -0
- package/src/shared/edge/config.ts +229 -0
- package/src/shared/edge/render.ts +221 -0
- package/src/shared/edge/runtime.ts +268 -0
- package/src/shared/edge/types.ts +62 -0
- package/src/shared/engine.ts +67 -0
- package/src/shared/environment/aws-profiles.ts +49 -0
- package/src/shared/environment/env-selector.ts +161 -0
- package/src/shared/environment/playwright-env.ts +82 -0
- package/src/shared/environment-manager/catalog.ts +77 -0
- package/src/shared/environment-manager/clone-guard.ts +163 -0
- package/src/shared/environment-manager/dag.ts +286 -0
- package/src/shared/environment-manager/default-workspace.ts +182 -0
- package/src/shared/environment-manager/derivation/alias.ts +90 -0
- package/src/shared/environment-manager/derivation/cache.ts +97 -0
- package/src/shared/environment-manager/derivation/derive-graph.ts +421 -0
- package/src/shared/environment-manager/derivation/derived-up.ts +354 -0
- package/src/shared/environment-manager/derivation/load-alias.ts +11 -0
- package/src/shared/environment-manager/derivation/rules-compose.ts +42 -0
- package/src/shared/environment-manager/derivation/rules-events.ts +50 -0
- package/src/shared/environment-manager/derivation/rules-http.ts +247 -0
- package/src/shared/environment-manager/derivation/rules-infra.ts +64 -0
- package/src/shared/environment-manager/derivation/rules-readiness.ts +96 -0
- package/src/shared/environment-manager/derivation/scan.ts +160 -0
- package/src/shared/environment-manager/derivation/text.ts +40 -0
- package/src/shared/environment-manager/derivation/types.ts +69 -0
- package/src/shared/environment-manager/health.ts +589 -0
- package/src/shared/environment-manager/index.ts +6 -0
- package/src/shared/environment-manager/load-applications.ts +78 -0
- package/src/shared/environment-manager/log-tail.ts +212 -0
- package/src/shared/environment-manager/make-targets.ts +78 -0
- package/src/shared/environment-manager/opctl.ts +334 -0
- package/src/shared/environment-manager/readiness.ts +93 -0
- package/src/shared/environment-manager/register-local.ts +72 -0
- package/src/shared/environment-manager/secrets-check.ts +260 -0
- package/src/shared/environment-manager/service-env.ts +110 -0
- package/src/shared/environment-manager/service-runner.ts +1588 -0
- package/src/shared/environment-manager/up-plan.ts +302 -0
- package/src/shared/environment-manager/workspace-manager.ts +905 -0
- package/src/shared/environment-manager/workspaces.ts +860 -0
- package/src/shared/manifest/deps.ts +27 -0
- package/src/shared/manifest/migrate-manifest.ts +101 -0
- package/src/shared/manifest/read-manifest.ts +160 -0
- package/src/shared/manifest/schema.ts +299 -0
- package/src/shared/manifest/service-links.ts +93 -0
- package/src/shared/manifest/validate-manifest.ts +140 -0
- package/src/shared/manifest/workspace-manifests.ts +92 -0
- package/src/shared/open-url.ts +122 -0
- package/src/shared/org.ts +44 -0
- package/src/shared/paths.ts +178 -0
- package/src/shared/perf/optional-fields.ts +105 -0
- package/src/shared/perf/report-normalizer.ts +404 -0
- package/src/shared/perf/report-paths.ts +19 -0
- package/src/shared/perf/report-store.ts +110 -0
- package/src/shared/perf/report-types.ts +70 -0
- package/src/shared/perf/test-paths.ts +25 -0
- package/src/shared/process/log-rotation.ts +147 -0
- package/src/shared/process/spawn-streaming.ts +229 -0
- package/src/shared/product.ts +92 -0
- package/src/shared/profile.ts +141 -0
- package/src/shared/repo-kind.ts +32 -0
- package/src/shared/reporting/jsonl-reporter.ts +131 -0
- package/src/shared/reporting/slack-reporter.ts +340 -0
- package/src/shared/results/result-reader.ts +266 -0
- package/src/shared/results/result-writer.ts +168 -0
- package/src/shared/secrets/doppler.ts +126 -0
- package/src/shared/secrets/env.ts +48 -0
- package/src/shared/secrets/index.ts +197 -0
- package/src/shared/secrets/keys.ts +33 -0
- package/src/shared/secrets/onepassword.ts +75 -0
- package/src/shared/secrets/types.ts +52 -0
- package/src/shared/service-url.ts +119 -0
- package/src/shared/smoke/branch-resolver.ts +141 -0
- package/src/shared/smoke/git-remote.ts +70 -0
- package/src/shared/smoke/repo-cloner.ts +151 -0
- package/src/shared/stacks/config.ts +137 -0
- package/src/shared/stacks/manifest-commands.ts +88 -0
- package/src/shared/stacks/render.ts +253 -0
- package/src/shared/stacks/runtime.ts +334 -0
- package/src/shared/stacks/types.ts +53 -0
- package/src/shared/terminal/tabs.ts +212 -0
- package/src/shared/test-discovery/module-scanner.ts +569 -0
- package/src/shared/types/index.ts +678 -0
- package/src/shared/ui-marker.ts +19 -0
- package/src/ui/cli/applications-command.ts +116 -0
- package/src/ui/cli/config-command.ts +68 -0
- package/src/ui/cli/create-main.ts +9 -0
- package/src/ui/cli/create.ts +360 -0
- package/src/ui/cli/edge-command.ts +91 -0
- package/src/ui/cli/flag-parser.ts +246 -0
- package/src/ui/cli/graph-command.ts +524 -0
- package/src/ui/cli/health-display.ts +63 -0
- package/src/ui/cli/index.ts +3656 -0
- package/src/ui/cli/init.ts +855 -0
- package/src/ui/cli/invocation-target.ts +175 -0
- package/src/ui/cli/logs-command.ts +104 -0
- package/src/ui/cli/module-selection.ts +31 -0
- package/src/ui/cli/prompts.ts +767 -0
- package/src/ui/cli/results-viewer.ts +436 -0
- package/src/ui/cli/secrets-preflight.ts +91 -0
- package/src/ui/cli/stack-command.ts +144 -0
- package/src/ui/cli/stalled-setup-recovery.ts +129 -0
- package/src/ui/cli/test-runner.ts +1312 -0
- package/src/ui/cli/web-command.ts +1073 -0
- package/src/ui/server/changelog-parser.ts +94 -0
- package/src/ui/server/daemon-reaper.ts +129 -0
- package/src/ui/server/editor-manager.ts +301 -0
- package/src/ui/server/github-service.ts +223 -0
- package/src/ui/server/http-helpers.ts +98 -0
- package/src/ui/server/index.ts +3236 -0
- package/src/ui/server/log-history.ts +452 -0
- package/src/ui/server/perf-report.ts +42 -0
- package/src/ui/server/public/environments.html +494 -0
- package/src/ui/server/public/favicon.ico +0 -0
- package/src/ui/server/public/header.js +1371 -0
- package/src/ui/server/public/index.html +2595 -0
- package/src/ui/server/public/local-dev.html +7405 -0
- package/src/ui/server/public/logs.html +1489 -0
- package/src/ui/server/public/perf-report.js +359 -0
- package/src/ui/server/public/release.html +2111 -0
- package/src/ui/server/public/services.html +1098 -0
- package/src/ui/server/public/workspace-picker.js +69 -0
- package/src/ui/server/release-deploy-session.ts +246 -0
- package/src/ui/server/release-service.ts +1125 -0
- package/src/ui/server/sudo-store.ts +111 -0
- package/src/ui/server/workspace-routes.ts +2154 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* setup-default-workspace
|
|
3
|
+
*
|
|
4
|
+
* Builds the "default" workspace non-interactively: every standard system repo,
|
|
5
|
+
* all managed. No prompts, no cloning at setup time — den clones each
|
|
6
|
+
* managed repo on first use, and per-repo mode is a one-click change in the web
|
|
7
|
+
* UX afterwards for anything you actively develop.
|
|
8
|
+
*
|
|
9
|
+
* The repo set is the union of:
|
|
10
|
+
* 1. shop-web (the entry system)
|
|
11
|
+
* 2. the committed release fleet (config/den.yml `release.repos`) — the
|
|
12
|
+
* authoritative list of standard system repos. A dependency-graph walk
|
|
13
|
+
* alone misses islands: control-plane has no deps and nothing depends on
|
|
14
|
+
* it, so no walk from shop-web can ever reach it.
|
|
15
|
+
* 3. a best-effort dependency walk from shop-web — catches deps that aren't
|
|
16
|
+
* in the release fleet, when sibling checkouts exist to read manifests
|
|
17
|
+
* from. On a bare machine this contributes nothing, and that's fine.
|
|
18
|
+
* 4. infra-stack — the shared local-infra provider. It only appears as a
|
|
19
|
+
* dependency inside OTHER repos' manifests, so on a machine with no
|
|
20
|
+
* checkouts neither the fleet nor the walk can discover it.
|
|
21
|
+
*
|
|
22
|
+
* Usage:
|
|
23
|
+
* make setup (called from Step 4)
|
|
24
|
+
* npx tsx src/scripts/setup-default-workspace.ts
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import * as fs from "fs";
|
|
28
|
+
import * as path from "path";
|
|
29
|
+
import { readManifest } from "../shared/manifest/read-manifest.js";
|
|
30
|
+
import { depService } from "../shared/manifest/deps.js";
|
|
31
|
+
import {
|
|
32
|
+
readWorkspacesFile,
|
|
33
|
+
writeWorkspacesFile,
|
|
34
|
+
} from "../shared/environment-manager/workspaces.js";
|
|
35
|
+
import { upsertCatalogEntry } from "../shared/environment-manager/catalog.js";
|
|
36
|
+
import { getGitHubCoords } from "../shared/smoke/git-remote.js";
|
|
37
|
+
import {
|
|
38
|
+
getReposRoot,
|
|
39
|
+
readDenConfig,
|
|
40
|
+
readReleaseConfig,
|
|
41
|
+
requireGithubOrg,
|
|
42
|
+
} from "../shared/den-config.js";
|
|
43
|
+
import type { WorkspaceServiceEntry } from "../shared/types/index.js";
|
|
44
|
+
|
|
45
|
+
import { product } from "../shared/product.js";
|
|
46
|
+
const WORKSPACE_KEY = "default";
|
|
47
|
+
|
|
48
|
+
/** The repo the dependency walk starts from: `defaults.workspace.entry`. */
|
|
49
|
+
function entryRepo(): string | undefined {
|
|
50
|
+
return readDenConfig().defaults?.workspace?.entry?.trim() || undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Repos invisible to both the release fleet and a manifest walk on a fresh
|
|
55
|
+
* machine: the shared local-infra repo (`graph.infra.repo`), if any.
|
|
56
|
+
*/
|
|
57
|
+
function extraStandardRepos(): string[] {
|
|
58
|
+
const infra = readDenConfig().graph?.infra?.repo?.trim();
|
|
59
|
+
return infra ? [infra] : [];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Extract unique dep repo names from a manifest (strips subsystem, e.g. "shop/api" → "shop"). */
|
|
63
|
+
function getDepsFromManifest(repoPath: string): string[] {
|
|
64
|
+
const manifest = readManifest(repoPath);
|
|
65
|
+
if (!manifest?.services) return [];
|
|
66
|
+
const deps = new Set<string>();
|
|
67
|
+
for (const svc of Object.values(manifest.services)) {
|
|
68
|
+
for (const rawDep of svc.depends_on ?? []) {
|
|
69
|
+
const dep = depService(rawDep);
|
|
70
|
+
deps.add(dep.includes("/") ? dep.split("/")[0] : dep);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return Array.from(deps);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* BFS through the dependency graph, only following repos that exist locally.
|
|
78
|
+
* Returns all reachable dep repo names (excludes startRepoName itself),
|
|
79
|
+
* ordered by discovery depth. Best-effort by construction: a repo that isn't
|
|
80
|
+
* checked out truncates its branch of the walk, which is why the release
|
|
81
|
+
* fleet — not this walk — is the primary seed source.
|
|
82
|
+
*/
|
|
83
|
+
function collectAllDeps(startRepoName: string, reposRoot: string): string[] {
|
|
84
|
+
const visited = new Set<string>([startRepoName]);
|
|
85
|
+
const ordered: string[] = [];
|
|
86
|
+
const queue: string[] = [path.join(reposRoot, startRepoName)];
|
|
87
|
+
|
|
88
|
+
while (queue.length > 0) {
|
|
89
|
+
const repoPath = queue.shift()!;
|
|
90
|
+
if (!fs.existsSync(repoPath)) continue;
|
|
91
|
+
|
|
92
|
+
for (const depName of getDepsFromManifest(repoPath)) {
|
|
93
|
+
if (!visited.has(depName)) {
|
|
94
|
+
visited.add(depName);
|
|
95
|
+
ordered.push(depName);
|
|
96
|
+
queue.push(path.join(reposRoot, depName));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return ordered;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Union of seed sources, deduped, the entry repo first. Pure given its inputs. */
|
|
105
|
+
export function computeSeedRepos(
|
|
106
|
+
fleetRepos: string[],
|
|
107
|
+
graphDeps: string[],
|
|
108
|
+
extras: string[] = [],
|
|
109
|
+
entry?: string,
|
|
110
|
+
): string[] {
|
|
111
|
+
const seen = new Set<string>();
|
|
112
|
+
const ordered: string[] = [];
|
|
113
|
+
for (const name of [entry, ...fleetRepos, ...graphDeps, ...extras]) {
|
|
114
|
+
if (!name || seen.has(name)) continue;
|
|
115
|
+
seen.add(name);
|
|
116
|
+
ordered.push(name);
|
|
117
|
+
}
|
|
118
|
+
return ordered;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Resolve the full seed list from live config + a best-effort manifest walk. Read-only. */
|
|
122
|
+
export function deriveSeedRepos(): string[] {
|
|
123
|
+
const reposRoot = getReposRoot();
|
|
124
|
+
const fleet = (readReleaseConfig().repos ?? [])
|
|
125
|
+
.filter((r) => r.enabled !== false)
|
|
126
|
+
.map((r) => r.name);
|
|
127
|
+
const entry = entryRepo();
|
|
128
|
+
return computeSeedRepos(
|
|
129
|
+
fleet,
|
|
130
|
+
entry ? collectAllDeps(entry, reposRoot) : [],
|
|
131
|
+
extraStandardRepos(),
|
|
132
|
+
entry,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Derive the GitHub slug from a local repo path, falling back to org/repoName. */
|
|
137
|
+
function ghSlugFor(repoPath: string, repoName: string, org: string): string {
|
|
138
|
+
const coords = getGitHubCoords(repoPath);
|
|
139
|
+
return coords ? `${coords.owner}/${coords.repo}` : `${org}/${repoName}`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function main() {
|
|
143
|
+
console.log(`\n ${product().cli} · Default Workspace Setup\n`);
|
|
144
|
+
console.log(
|
|
145
|
+
' This builds the "default" workspace — every standard system repo,\n' +
|
|
146
|
+
` all managed: ${product().cli} clones and keeps each one up to date for\n` +
|
|
147
|
+
" you, no checkouts or decisions required. For anything you actively\n" +
|
|
148
|
+
" develop, flip that repo to dev-managed in the web UX (Local Dev)\n" +
|
|
149
|
+
" and point it at your own checkout.\n",
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const reposRoot = getReposRoot();
|
|
153
|
+
const org = requireGithubOrg();
|
|
154
|
+
const seed = deriveSeedRepos();
|
|
155
|
+
|
|
156
|
+
const services: Record<string, WorkspaceServiceEntry> = {};
|
|
157
|
+
for (const repoName of seed) {
|
|
158
|
+
const localPath = path.join(reposRoot, repoName);
|
|
159
|
+
const exists = fs.existsSync(localPath);
|
|
160
|
+
const slug = exists
|
|
161
|
+
? ghSlugFor(localPath, repoName, org)
|
|
162
|
+
: `${org}/${repoName}`;
|
|
163
|
+
|
|
164
|
+
services[repoName] = { mode: "managed", branch: "main" };
|
|
165
|
+
upsertCatalogEntry(repoName, { gh: slug });
|
|
166
|
+
|
|
167
|
+
// Every row gets a trailer — a bare row in a column of annotated rows
|
|
168
|
+
// reads as "skipped" even though the entry was written either way.
|
|
169
|
+
console.log(
|
|
170
|
+
` ✓ ${repoName.padEnd(18)} → managed (main)${
|
|
171
|
+
exists
|
|
172
|
+
? ` local checkout at ${localPath} left untouched`
|
|
173
|
+
: ` no local checkout — ${product().cli} clones it on first use`
|
|
174
|
+
}`,
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const wsFile = readWorkspacesFile();
|
|
179
|
+
wsFile.workspaces[WORKSPACE_KEY] = { services };
|
|
180
|
+
writeWorkspacesFile(wsFile);
|
|
181
|
+
|
|
182
|
+
console.log(
|
|
183
|
+
`\n ✓ Default workspace configured with ${seed.length} service(s), all managed.`,
|
|
184
|
+
);
|
|
185
|
+
console.log(
|
|
186
|
+
" Change any repo to dev-managed in the web UX: make web → Local Dev.",
|
|
187
|
+
);
|
|
188
|
+
console.log(` Run 'make ${product().cli}-up' to start your services.\n`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Importable without side effects (tests import computeSeedRepos/deriveSeedRepos);
|
|
192
|
+
// main runs only when executed directly. argv-based rather than import.meta:
|
|
193
|
+
// jest's CJS transform rejects import.meta, and this file must be importable
|
|
194
|
+
// under test.
|
|
195
|
+
const isDirectRun = Boolean(
|
|
196
|
+
process.argv[1] && /setup-default-workspace\.(ts|js)$/.test(process.argv[1]),
|
|
197
|
+
);
|
|
198
|
+
if (isDirectRun) {
|
|
199
|
+
main().catch((err) => {
|
|
200
|
+
console.error(err);
|
|
201
|
+
process.exit(1);
|
|
202
|
+
});
|
|
203
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Applications: the boundary between an org and its repos.
|
|
3
|
+
*
|
|
4
|
+
* Org > Application > Repo > Services
|
|
5
|
+
*
|
|
6
|
+
* - declared: `applications:` in config/den.yml, plus any repo whose own
|
|
7
|
+
* `.den.yml` sets `application:` (the repo's own setting wins);
|
|
8
|
+
* - repo: every other repo is its own application, named after the repo
|
|
9
|
+
* (a mono-repo: Application == Repo).
|
|
10
|
+
*
|
|
11
|
+
* An application's `repos` are the ones with a runtime (services). Modules and
|
|
12
|
+
* libraries are placed the same way but listed as `contributors`: code that
|
|
13
|
+
* ships inside another repo's runtime, with no status of its own.
|
|
14
|
+
*
|
|
15
|
+
* Pure: callers pass the config, manifest applications and kinds.
|
|
16
|
+
*/
|
|
17
|
+
import type { ApplicationConfig } from "./den-config.js";
|
|
18
|
+
import type { RepoKind } from "./types/index.js";
|
|
19
|
+
|
|
20
|
+
export interface ApplicationContributor {
|
|
21
|
+
repo: string;
|
|
22
|
+
kind: Exclude<RepoKind, "service">;
|
|
23
|
+
/** Repos whose runtime this code ships in. */
|
|
24
|
+
contributesTo: string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface Application {
|
|
28
|
+
name: string;
|
|
29
|
+
title: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
/** Who builds it. */
|
|
32
|
+
owner?: string;
|
|
33
|
+
/** declared in config or a manifest, or a repo standing as its own application. */
|
|
34
|
+
source: "declared" | "repo";
|
|
35
|
+
/** Repos with a runtime: these get status, up and down. */
|
|
36
|
+
repos: string[];
|
|
37
|
+
/** Modules and libraries in the application: no runtime of their own. */
|
|
38
|
+
contributors: ApplicationContributor[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function resolveApplications(opts: {
|
|
42
|
+
/** Repos to place (normally the workspace's). */
|
|
43
|
+
repos: string[];
|
|
44
|
+
config?: Record<string, ApplicationConfig>;
|
|
45
|
+
/** repo → application named in that repo's manifest. */
|
|
46
|
+
manifestApplications?: Record<string, string>;
|
|
47
|
+
/** repo → kind; repos not listed are services. */
|
|
48
|
+
kinds?: Record<string, RepoKind>;
|
|
49
|
+
/** repo → repos it contributes to (for modules and libraries). */
|
|
50
|
+
contributesTo?: Record<string, string[]>;
|
|
51
|
+
}): Application[] {
|
|
52
|
+
const inScope = new Set(opts.repos);
|
|
53
|
+
const placed = new Set<string>();
|
|
54
|
+
const apps = new Map<string, Application>();
|
|
55
|
+
const declare = (name: string): Application => {
|
|
56
|
+
let a = apps.get(name);
|
|
57
|
+
if (!a) {
|
|
58
|
+
const c = opts.config?.[name];
|
|
59
|
+
a = {
|
|
60
|
+
name,
|
|
61
|
+
title: c?.title ?? name,
|
|
62
|
+
...(c?.description ? { description: c.description } : {}),
|
|
63
|
+
...(c?.owner ? { owner: c.owner } : {}),
|
|
64
|
+
source: "declared",
|
|
65
|
+
repos: [],
|
|
66
|
+
contributors: [],
|
|
67
|
+
};
|
|
68
|
+
apps.set(name, a);
|
|
69
|
+
}
|
|
70
|
+
return a;
|
|
71
|
+
};
|
|
72
|
+
const place = (a: Application, repo: string) => {
|
|
73
|
+
if (!inScope.has(repo) || placed.has(repo)) return;
|
|
74
|
+
placed.add(repo);
|
|
75
|
+
a.repos.push(repo);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Config order first; declared applications exist even when none of their
|
|
79
|
+
// repos are in scope.
|
|
80
|
+
for (const name of Object.keys(opts.config ?? {})) declare(name);
|
|
81
|
+
// A repo's own manifest wins over the team list.
|
|
82
|
+
for (const [repo, name] of Object.entries(opts.manifestApplications ?? {}))
|
|
83
|
+
place(declare(name), repo);
|
|
84
|
+
for (const [name, c] of Object.entries(opts.config ?? {}))
|
|
85
|
+
for (const repo of c.repos ?? []) place(declare(name), repo);
|
|
86
|
+
|
|
87
|
+
// Every other repo is its own application. A declared application that
|
|
88
|
+
// already carries the repo's name takes it in instead.
|
|
89
|
+
const standalone: Application[] = [];
|
|
90
|
+
for (const repo of [...opts.repos].sort()) {
|
|
91
|
+
if (placed.has(repo)) continue;
|
|
92
|
+
const named = apps.get(repo);
|
|
93
|
+
if (named) {
|
|
94
|
+
place(named, repo);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
placed.add(repo);
|
|
98
|
+
standalone.push({
|
|
99
|
+
name: repo,
|
|
100
|
+
title: repo,
|
|
101
|
+
source: "repo",
|
|
102
|
+
repos: [repo],
|
|
103
|
+
contributors: [],
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return [...apps.values(), ...standalone].map((a) =>
|
|
108
|
+
splitByKind(a, opts.kinds, opts.contributesTo),
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function splitByKind(
|
|
113
|
+
a: Application,
|
|
114
|
+
kinds: Record<string, RepoKind> = {},
|
|
115
|
+
contributesTo: Record<string, string[]> = {},
|
|
116
|
+
): Application {
|
|
117
|
+
const repos: string[] = [];
|
|
118
|
+
const contributors: ApplicationContributor[] = [];
|
|
119
|
+
for (const repo of [...a.repos].sort()) {
|
|
120
|
+
const kind = kinds[repo] ?? "service";
|
|
121
|
+
if (kind === "service") repos.push(repo);
|
|
122
|
+
else
|
|
123
|
+
contributors.push({
|
|
124
|
+
repo,
|
|
125
|
+
kind,
|
|
126
|
+
contributesTo: contributesTo[repo] ?? [],
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return { ...a, repos, contributors };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** The application named `name`. */
|
|
133
|
+
export function findApplication(
|
|
134
|
+
apps: Application[],
|
|
135
|
+
name: string,
|
|
136
|
+
): Application | undefined {
|
|
137
|
+
return apps.find((a) => a.name === name);
|
|
138
|
+
}
|