canopycms 0.0.67 → 0.0.68-int.94
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 +3 -2
- package/dist/ai/handler.js +8 -0
- package/dist/api/admin-branch-health.js +12 -7
- package/dist/api/admin.d.ts +21 -9
- package/dist/api/admin.js +18 -2
- package/dist/api/branch-status.js +19 -4
- package/dist/api/branch.js +11 -11
- package/dist/api/client.d.ts +12 -0
- package/dist/api/client.js +34 -11
- package/dist/api/content.d.ts +6 -5
- package/dist/api/content.js +44 -41
- package/dist/api/entries.js +16 -15
- package/dist/api/github-sync.d.ts +10 -1
- package/dist/api/github-sync.js +20 -10
- package/dist/api/reference-options.js +1 -1
- package/dist/api/resolve-references.js +14 -40
- package/dist/api/settings-helpers.d.ts +1 -1
- package/dist/api/settings-helpers.js +1 -4
- package/dist/api/user.d.ts +3 -0
- package/dist/api/user.js +3 -0
- package/dist/assets/factory.d.ts +5 -0
- package/dist/assets/factory.js +5 -0
- package/dist/authorization/content.d.ts +5 -4
- package/dist/authorization/content.js +5 -5
- package/dist/authorization/path.d.ts +11 -6
- package/dist/authorization/path.js +11 -6
- package/dist/authorization/types.d.ts +2 -2
- package/dist/branch-health.js +3 -3
- package/dist/branch-schema-cache.d.ts +5 -3
- package/dist/branch-schema-cache.js +29 -11
- package/dist/branch-workspace.js +8 -3
- package/dist/build-identity.d.ts +3 -0
- package/dist/build-identity.js +13 -0
- package/dist/cli/cli.js +1070 -388
- package/dist/cli/generate-ai-content.js +537 -150
- package/dist/cli/github-app-manifest.d.ts +4 -3
- package/dist/cli/github-app-manifest.js +4 -3
- package/dist/cli/init.js +21 -11
- package/dist/cli/migrate.js +12 -8
- package/dist/cli/sync.js +83 -37
- package/dist/cli/template-files/Dockerfile.cms.template +8 -0
- package/dist/cli/template-files/cdk-app.ts.template +4 -0
- package/dist/cli/template-files/cms-stack.ts.template +6 -0
- package/dist/cli/template-files/deploy-cms.yml.template +2 -0
- package/dist/config/schemas/config.d.ts +11 -3
- package/dist/config/schemas/config.js +5 -1
- package/dist/config/schemas/field.js +1 -0
- package/dist/config/schemas/url.d.ts +2 -0
- package/dist/config/schemas/url.js +7 -0
- package/dist/config/types.d.ts +28 -4
- package/dist/config/validation.d.ts +6 -0
- package/dist/config/validation.js +37 -0
- package/dist/content-listing.d.ts +12 -12
- package/dist/content-listing.js +10 -6
- package/dist/content-reader.d.ts +11 -2
- package/dist/content-reader.js +22 -14
- package/dist/content-store.d.ts +37 -9
- package/dist/content-store.js +70 -43
- package/dist/content-tree.d.ts +1 -1
- package/dist/content-tree.js +2 -2
- package/dist/context.d.ts +27 -9
- package/dist/context.js +154 -70
- package/dist/editor/CanopyEditor.d.ts +1 -1
- package/dist/editor/CanopyEditor.js +1 -1
- package/dist/editor/Editor.d.ts +2 -0
- package/dist/editor/Editor.js +6 -5
- package/dist/editor/FormRenderer.js +20 -5
- package/dist/editor/admin/SystemHealthPanel.js +45 -7
- package/dist/editor/components/NoEditPermissionNotice.d.ts +10 -0
- package/dist/editor/components/NoEditPermissionNotice.js +17 -0
- package/dist/editor/editor-utils.d.ts +17 -15
- package/dist/editor/editor-utils.js +43 -36
- package/dist/editor/hooks/useBranchesData.js +3 -1
- package/dist/editor/hooks/useCommentSystem.js +5 -1
- package/dist/editor/hooks/useDraftManager.d.ts +1 -1
- package/dist/editor/hooks/useDraftManager.js +2 -1
- package/dist/editor/hooks/useEntriesData.js +2 -2
- package/dist/editor/hooks/useEntryManager.js +17 -11
- package/dist/editor/preview-bridge.js +4 -1
- package/dist/editor/preview-path.d.ts +10 -0
- package/dist/editor/preview-path.js +20 -0
- package/dist/entry-schema-registry.d.ts +4 -4
- package/dist/entry-schema-registry.js +10 -6
- package/dist/entry-schema.d.ts +27 -4
- package/dist/entry-schema.js +20 -3
- package/dist/git-manager.d.ts +79 -5
- package/dist/git-manager.js +308 -18
- package/dist/github-service.d.ts +8 -0
- package/dist/github-service.js +5 -1
- package/dist/http/handler.js +35 -13
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +2 -0
- package/dist/http/router.d.ts +2 -0
- package/dist/http/router.js +2 -1
- package/dist/http/worker-not-ready.d.ts +9 -0
- package/dist/http/worker-not-ready.js +17 -0
- package/dist/operating-mode/client-unsafe-strategy.js +0 -6
- package/dist/operating-mode/types.d.ts +0 -3
- package/dist/paths/branch-name.d.ts +5 -0
- package/dist/paths/branch-name.js +9 -0
- package/dist/paths/branch.d.ts +6 -1
- package/dist/paths/branch.js +15 -2
- package/dist/paths/index.d.ts +3 -3
- package/dist/paths/index.js +3 -3
- package/dist/paths/normalize.d.ts +7 -0
- package/dist/paths/normalize.js +9 -0
- package/dist/reference-resolver.d.ts +5 -21
- package/dist/reference-resolver.js +9 -44
- package/dist/resolve-canopy-user.js +2 -1
- package/dist/schema/schema-store.d.ts +48 -22
- package/dist/schema/schema-store.js +66 -22
- package/dist/services.d.ts +18 -6
- package/dist/services.js +85 -70
- package/dist/settings-workspace.js +42 -4
- package/dist/static/seo.d.ts +2 -14
- package/dist/static/seo.js +2 -25
- package/dist/submission-attribution.d.ts +73 -0
- package/dist/submission-attribution.js +221 -0
- package/dist/sync-core.d.ts +12 -1
- package/dist/sync-core.js +31 -13
- package/dist/task-queue/worker-status.d.ts +8 -0
- package/dist/task-queue/worker-status.js +17 -0
- package/dist/types.d.ts +31 -2
- package/dist/utils/content-write-lock.d.ts +18 -7
- package/dist/utils/content-write-lock.js +18 -9
- package/dist/utils/debug.d.ts +8 -0
- package/dist/utils/debug.js +10 -2
- package/dist/utils/git.d.ts +28 -0
- package/dist/utils/git.js +38 -0
- package/dist/utils/provisioning-lock.d.ts +15 -5
- package/dist/utils/provisioning-lock.js +31 -11
- package/dist/utils/request-timing.d.ts +25 -0
- package/dist/utils/request-timing.js +101 -0
- package/dist/utils/url-prefix.d.ts +30 -0
- package/dist/utils/url-prefix.js +61 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +3 -0
- package/dist/worker/canopy-state.d.ts +45 -0
- package/dist/worker/canopy-state.js +75 -0
- package/dist/worker/cms-worker.js +23 -2
- package/dist/worker/git-sync.d.ts +8 -2
- package/dist/worker/git-sync.js +138 -24
- package/dist/worker/provisioned-workspace.d.ts +35 -0
- package/dist/worker/provisioned-workspace.js +50 -0
- package/dist/worker/rebase.d.ts +1 -1
- package/dist/worker/rebase.js +83 -12
- package/dist/worker/task-runner.js +39 -4
- package/package.json +1 -1
|
@@ -5,8 +5,8 @@ function normalize(p) {
|
|
|
5
5
|
const normalized = p.split(path.sep).join('/');
|
|
6
6
|
return normalized.replace(/^\.?\/*/, '');
|
|
7
7
|
}
|
|
8
|
-
function matchesRule(rule,
|
|
9
|
-
return minimatch(
|
|
8
|
+
function matchesRule(rule, logicalPath) {
|
|
9
|
+
return minimatch(logicalPath, rule.path, { dot: true });
|
|
10
10
|
}
|
|
11
11
|
function isAllowedByTarget(target, user) {
|
|
12
12
|
const hasUserConstraint = !!target.allowedUsers?.length;
|
|
@@ -32,12 +32,17 @@ export function resolveDefaultPathAccess(defaultAccess, level) {
|
|
|
32
32
|
return defaultAccess[level] ?? 'deny';
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
* Evaluate access for a
|
|
36
|
-
*
|
|
35
|
+
* Evaluate access for a path against config-defined rules. First matching rule wins;
|
|
36
|
+
* defaultAccess applies when none matches.
|
|
37
|
+
*
|
|
38
|
+
* Rule globs and the checked path are both LOGICAL paths: content-root-prefixed and
|
|
39
|
+
* id-free, the space the Permission Manager writes rules in. An entry's logical path is
|
|
40
|
+
* `<collection logical path>/<slug>` (`entryLogicalPath`), e.g. `content/blog/my-post`, never
|
|
41
|
+
* its on-disk `content/blog.<id>/post.my-post.<id>.json`.
|
|
37
42
|
* @internal Exported for tests.
|
|
38
43
|
*/
|
|
39
|
-
export function checkPathAccess({ rules,
|
|
40
|
-
const normalizedPath = normalize(
|
|
44
|
+
export function checkPathAccess({ rules, logicalPath, user, defaultAccess, level, }) {
|
|
45
|
+
const normalizedPath = normalize(logicalPath);
|
|
41
46
|
// Only Admins bypass all path permissions
|
|
42
47
|
if (isAdmin(user.groups)) {
|
|
43
48
|
return { allowed: true, reason: 'admin' };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A path used in permission rules, e.g. "content/posts"
|
|
3
|
-
* SECURITY CRITICAL: always validated to prevent path traversal.
|
|
2
|
+
* A logical-path glob used in permission rules, e.g. "content/posts/**" (see
|
|
3
|
+
* `PathPermission.path`). SECURITY CRITICAL: always validated to prevent path traversal.
|
|
4
4
|
*/
|
|
5
5
|
export type PermissionPath = string & {
|
|
6
6
|
readonly __brand: 'PermissionPath';
|
package/dist/branch-health.js
CHANGED
|
@@ -5,16 +5,16 @@ import { ContentIdIndex } from './content-id-index.js';
|
|
|
5
5
|
import { sanitizeBranchName } from './paths/branch-name.js';
|
|
6
6
|
import { getErrorMessage, isNodeError, isNotFoundError } from './utils/error.js';
|
|
7
7
|
import { isRebaseInProgress } from './utils/git.js';
|
|
8
|
+
import { branchProvisioningLockName } from './utils/provisioning-lock.js';
|
|
8
9
|
/**
|
|
9
|
-
* The provisioning lock marker's path for a branch directory
|
|
10
|
-
* `branch-workspace.ts`'s `ensureGitWorkspace()` passes exactly.
|
|
10
|
+
* The provisioning lock marker's path for a branch directory.
|
|
11
11
|
*
|
|
12
12
|
* `acquireProvisioningLock` passes the name as `lockfilePath`, overriding
|
|
13
13
|
* proper-lockfile's default `${target}.lock`, so the marker (a mkdir-based
|
|
14
14
|
* directory) sits at exactly this path — no extra `.lock` suffix.
|
|
15
15
|
*/
|
|
16
16
|
function provisioningLockPath(baseRoot, dirName) {
|
|
17
|
-
return path.join(baseRoot,
|
|
17
|
+
return path.join(baseRoot, branchProvisioningLockName(dirName));
|
|
18
18
|
}
|
|
19
19
|
/** Stat the provisioning lock marker, if present. Never throws. */
|
|
20
20
|
async function readProvisioningLock(baseRoot, dirName) {
|
|
@@ -2,6 +2,8 @@ import type { RootCollectionConfig } from './config/index.js';
|
|
|
2
2
|
import type { FlatSchemaItem } from './config/types.js';
|
|
3
3
|
import type { OperatingMode } from './operating-mode/index.js';
|
|
4
4
|
import type { EntrySchemaRegistry, SchemaResolutionResult } from './schema/types.js';
|
|
5
|
+
/** File name of the schema cache inside {@link schemaCacheDir}. */
|
|
6
|
+
export declare const SCHEMA_CACHE_FILE = "schema-cache.json";
|
|
5
7
|
/** resource-generation.ts resource key for the schema cache's marker. */
|
|
6
8
|
export declare const SCHEMA_GENERATION_RESOURCE = "schema";
|
|
7
9
|
/** @internal Exported for tests. */
|
|
@@ -18,8 +20,8 @@ export interface BranchSchemaCacheEntry {
|
|
|
18
20
|
generation: string | null;
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
|
-
* Per-branch schema cache:
|
|
22
|
-
*
|
|
23
|
+
* Per-branch schema cache: one file in {@link schemaCacheDir} with no in-memory
|
|
24
|
+
* layer, so it stays coherent across Lambda invocations.
|
|
23
25
|
*
|
|
24
26
|
* Freshness follows the generation-marker protocol owned by
|
|
25
27
|
* resource-generation.ts, and this is one of that protocol's durable-snapshot
|
|
@@ -39,7 +41,7 @@ export declare class BranchSchemaCache {
|
|
|
39
41
|
/**
|
|
40
42
|
* Whether to skip the on-disk cache for this branchRoot.
|
|
41
43
|
*
|
|
42
|
-
* Never write
|
|
44
|
+
* Never write a schema cache at the project root, whichever entrypoint
|
|
43
45
|
* produced the cwd branchRoot. branchRoot equals process.cwd() only in the
|
|
44
46
|
* synthetic contexts static deployments and build phases use; a real branch
|
|
45
47
|
* root is always nested under the workspace.
|
|
@@ -5,10 +5,14 @@ import { flattenSchema } from './config/flatten.js';
|
|
|
5
5
|
import { validateReferenceEntryTypes } from './validation/entry-type-reference-validator.js';
|
|
6
6
|
import { isBuildMode } from './build-mode.js';
|
|
7
7
|
import { bumpResourceGeneration, readResourceGeneration, isGenerationCurrent, } from './resource-generation.js';
|
|
8
|
+
import { timeRequestPhase } from './utils/request-timing.js';
|
|
9
|
+
import { CANOPY_META_DIR } from './utils/git.js';
|
|
8
10
|
/** Bump when BranchSchemaCacheEntry shape changes to auto-invalidate stale caches */
|
|
9
11
|
const SCHEMA_CACHE_VERSION = 3;
|
|
10
12
|
/** Minimum interval between mtime staleness checks (ms) */
|
|
11
13
|
const MTIME_CHECK_DEBOUNCE_MS = 1000;
|
|
14
|
+
/** File name of the schema cache inside {@link schemaCacheDir}. */
|
|
15
|
+
export const SCHEMA_CACHE_FILE = 'schema-cache.json';
|
|
12
16
|
/** resource-generation.ts resource key for the schema cache's marker. */
|
|
13
17
|
export const SCHEMA_GENERATION_RESOURCE = 'schema';
|
|
14
18
|
/**
|
|
@@ -43,8 +47,22 @@ async function isStaleByMtime(dir, cachedAt) {
|
|
|
43
47
|
return false;
|
|
44
48
|
}
|
|
45
49
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
50
|
+
* Directory holding a branch's schema cache: `{branchRoot}/.git/canopycms` when
|
|
51
|
+
* the branch root is a full clone (every canopycms branch workspace is), else
|
|
52
|
+
* `{branchRoot}/.canopy-meta`. Under `.git/` because nothing there is ever
|
|
53
|
+
* tracked or reported by `git status`, so the cache can neither dirty the
|
|
54
|
+
* workspace nor enter a commit, even where an adopter has committed
|
|
55
|
+
* `.canopy-meta/`. It also lives and dies with the clone, so a re-clone never
|
|
56
|
+
* reads its predecessor's snapshot.
|
|
57
|
+
*/
|
|
58
|
+
async function schemaCacheDir(branchRoot) {
|
|
59
|
+
const gitDir = path.join(branchRoot, '.git');
|
|
60
|
+
const isClone = await fs.stat(gitDir).then((stat) => stat.isDirectory(), () => false);
|
|
61
|
+
return isClone ? path.join(gitDir, 'canopycms') : path.join(branchRoot, CANOPY_META_DIR);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Per-branch schema cache: one file in {@link schemaCacheDir} with no in-memory
|
|
65
|
+
* layer, so it stays coherent across Lambda invocations.
|
|
48
66
|
*
|
|
49
67
|
* Freshness follows the generation-marker protocol owned by
|
|
50
68
|
* resource-generation.ts, and this is one of that protocol's durable-snapshot
|
|
@@ -65,7 +83,7 @@ export class BranchSchemaCache {
|
|
|
65
83
|
/**
|
|
66
84
|
* Whether to skip the on-disk cache for this branchRoot.
|
|
67
85
|
*
|
|
68
|
-
* Never write
|
|
86
|
+
* Never write a schema cache at the project root, whichever entrypoint
|
|
69
87
|
* produced the cwd branchRoot. branchRoot equals process.cwd() only in the
|
|
70
88
|
* synthetic contexts static deployments and build phases use; a real branch
|
|
71
89
|
* root is always nested under the workspace.
|
|
@@ -75,7 +93,7 @@ export class BranchSchemaCache {
|
|
|
75
93
|
}
|
|
76
94
|
/** Get schema for a branch, from the cache when fresh, else resolved fresh. */
|
|
77
95
|
async getSchema(branchRoot, entrySchemaRegistry, contentRootName = 'content') {
|
|
78
|
-
return this.loadFromCacheOrResolve(branchRoot, entrySchemaRegistry, contentRootName);
|
|
96
|
+
return timeRequestPhase('schema', () => this.loadFromCacheOrResolve(branchRoot, entrySchemaRegistry, contentRootName));
|
|
79
97
|
}
|
|
80
98
|
/**
|
|
81
99
|
* Resolve the schema from disk. Protected rather than a direct resolveSchema
|
|
@@ -89,8 +107,7 @@ export class BranchSchemaCache {
|
|
|
89
107
|
const contentRoot = path.join(branchRoot, contentRootName);
|
|
90
108
|
const skipDiskCache = this.skipDiskCache(branchRoot);
|
|
91
109
|
if (!skipDiskCache) {
|
|
92
|
-
const
|
|
93
|
-
const cachePath = path.join(cacheDir, 'schema-cache.json');
|
|
110
|
+
const cachePath = path.join(await schemaCacheDir(branchRoot), SCHEMA_CACHE_FILE);
|
|
94
111
|
let cacheData = null;
|
|
95
112
|
try {
|
|
96
113
|
const cacheContent = await fs.readFile(cachePath, 'utf-8');
|
|
@@ -149,7 +166,8 @@ export class BranchSchemaCache {
|
|
|
149
166
|
const read = skipDiskCache
|
|
150
167
|
? null
|
|
151
168
|
: await readResourceGeneration(branchRoot, SCHEMA_GENERATION_RESOURCE);
|
|
152
|
-
|
|
169
|
+
// Nested under `schema`, so a request summary names a cache miss (`…schema>resolve`).
|
|
170
|
+
const result = await timeRequestPhase('resolve', () => this.resolveFresh(contentRoot, entrySchemaRegistry));
|
|
153
171
|
// Validate schema has content
|
|
154
172
|
if (!isValidSchema(result.schema)) {
|
|
155
173
|
throw new Error(`No schema found in ${contentRoot}. Create .collection.json files ` +
|
|
@@ -166,11 +184,11 @@ export class BranchSchemaCache {
|
|
|
166
184
|
// Use configured contentRoot name as base path for logical paths
|
|
167
185
|
const flatSchema = flattenSchema(result.schema, contentRootName);
|
|
168
186
|
if (!skipDiskCache) {
|
|
169
|
-
const cacheDir =
|
|
170
|
-
const cachePath = path.join(cacheDir,
|
|
187
|
+
const cacheDir = await schemaCacheDir(branchRoot);
|
|
188
|
+
const cachePath = path.join(cacheDir, SCHEMA_CACHE_FILE);
|
|
171
189
|
// Opportunistic cleanup of the retired .stale marker file, which a
|
|
172
190
|
// mid-flight deploy can leave behind. Not load-bearing.
|
|
173
|
-
await fs.unlink(path.join(
|
|
191
|
+
await fs.unlink(path.join(branchRoot, CANOPY_META_DIR, 'schema-cache.stale')).catch(() => { });
|
|
174
192
|
if (read && read.ok) {
|
|
175
193
|
const newCache = {
|
|
176
194
|
version: SCHEMA_CACHE_VERSION,
|
|
@@ -180,7 +198,7 @@ export class BranchSchemaCache {
|
|
|
180
198
|
generation: read.token,
|
|
181
199
|
};
|
|
182
200
|
// Temp file then rename, with the temp file unlinked on a failed
|
|
183
|
-
// rename so a transient error leaves no stray `.tmp`
|
|
201
|
+
// rename so a transient error leaves no stray `.tmp` beside the cache.
|
|
184
202
|
await fs.mkdir(cacheDir, { recursive: true });
|
|
185
203
|
const tmpPath = path.join(cacheDir, `schema-cache.tmp.${Date.now()}.${Math.random()}.json`);
|
|
186
204
|
await fs.writeFile(tmpPath, JSON.stringify(newCache, null, 2), 'utf-8');
|
package/dist/branch-workspace.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { ensureBranchRoot } from './paths/index.js';
|
|
2
|
+
import { BranchPathError, ensureBranchRoot, isSettingsBranchName } from './paths/index.js';
|
|
3
3
|
import { getBranchMetadataFileManager, loadBranchContext } from './branch-metadata.js';
|
|
4
4
|
import { readsFromCheckout } from './build-mode.js';
|
|
5
5
|
import { operatingStrategy } from './operating-mode/index.js';
|
|
6
6
|
import { GitManager } from './git-manager.js';
|
|
7
7
|
import { createDebugLogger } from './utils/debug.js';
|
|
8
8
|
import { resolveBaseBranch } from './utils/git.js';
|
|
9
|
-
import { acquireProvisioningLock } from './utils/provisioning-lock.js';
|
|
9
|
+
import { acquireProvisioningLock, branchProvisioningLockName } from './utils/provisioning-lock.js';
|
|
10
10
|
const log = createDebugLogger({ prefix: 'BranchWorkspace' });
|
|
11
11
|
// In-memory lock to prevent concurrent workspace initialization
|
|
12
12
|
const workspaceInitLocks = new Map();
|
|
@@ -41,7 +41,7 @@ export class BranchWorkspaceManager {
|
|
|
41
41
|
branchName: options.branchName,
|
|
42
42
|
mode: options.mode,
|
|
43
43
|
});
|
|
44
|
-
releaseLock = await acquireProvisioningLock(path.dirname(options.branchRoot),
|
|
44
|
+
releaseLock = await acquireProvisioningLock(path.dirname(options.branchRoot), branchProvisioningLockName(path.basename(options.branchRoot)));
|
|
45
45
|
await GitManager.initializeWorkspace({
|
|
46
46
|
workspacePath: options.branchRoot,
|
|
47
47
|
branchName: options.branchName,
|
|
@@ -77,6 +77,11 @@ export class BranchWorkspaceManager {
|
|
|
77
77
|
}
|
|
78
78
|
async openOrCreateBranch(options) {
|
|
79
79
|
const { branchName, mode, basePathOverride, title, description, access, createdBy, remoteUrl } = options;
|
|
80
|
+
// resolveBranchPath refuses the reserved prefix; this also refuses an adopter's
|
|
81
|
+
// configured settings branch name, which only the config knows.
|
|
82
|
+
if (isSettingsBranchName(branchName, operatingStrategy(mode).getSettingsBranchName(this.config))) {
|
|
83
|
+
throw new BranchPathError('Settings branches are not content branches');
|
|
84
|
+
}
|
|
80
85
|
const { branchRoot, baseRoot, branchName: safeName, } = await ensureBranchRoot({
|
|
81
86
|
mode,
|
|
82
87
|
branchName,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CANOPYCMS_VERSION } from './version.js';
|
|
2
|
+
/**
|
|
3
|
+
* Set by the image build (Dockerfile.cms `ARG`), not by the infrastructure: a Lambda env var
|
|
4
|
+
* would name the infrastructure's commit and hide an image/infrastructure skew.
|
|
5
|
+
*/
|
|
6
|
+
const SOURCE_REVISION_ENV = 'CANOPY_SOURCE_SHA';
|
|
7
|
+
export function getBuildIdentity(env = process.env) {
|
|
8
|
+
// The Dockerfile sets the variable to the empty string when the build arg is not passed.
|
|
9
|
+
const sourceRevision = env[SOURCE_REVISION_ENV]?.trim();
|
|
10
|
+
return sourceRevision
|
|
11
|
+
? { canopycmsVersion: CANOPYCMS_VERSION, sourceRevision }
|
|
12
|
+
: { canopycmsVersion: CANOPYCMS_VERSION };
|
|
13
|
+
}
|