canopycms 0.0.0 → 0.0.2
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/dist/auth/plugin.d.ts +8 -0
- package/dist/auth/plugin.d.ts.map +1 -1
- package/dist/build-mode.d.ts +15 -5
- package/dist/build-mode.d.ts.map +1 -1
- package/dist/build-mode.js +18 -8
- package/dist/build-mode.js.map +1 -1
- package/dist/cli/init.d.ts +2 -2
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +37 -36
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/template-files/ai-config.ts.template +21 -0
- package/dist/cli/template-files/ai-route.ts.template +10 -0
- package/dist/cli/template-files/canopy.ts.template +24 -0
- package/dist/cli/templates.d.ts +5 -1
- package/dist/cli/templates.d.ts.map +1 -1
- package/dist/cli/templates.js +9 -2
- package/dist/cli/templates.js.map +1 -1
- package/dist/config/schemas/config.d.ts +4 -0
- package/dist/config/schemas/config.d.ts.map +1 -1
- package/dist/config/schemas/config.js +2 -0
- package/dist/config/schemas/config.js.map +1 -1
- package/dist/config/types.d.ts +5 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/content-reader.js +2 -2
- package/dist/content-reader.js.map +1 -1
- package/dist/context.js +5 -5
- package/dist/context.js.map +1 -1
- package/dist/operating-mode/client-unsafe-strategy.d.ts.map +1 -1
- package/dist/operating-mode/client-unsafe-strategy.js +15 -18
- package/dist/operating-mode/client-unsafe-strategy.js.map +1 -1
- package/dist/operating-mode/types.d.ts +8 -0
- package/dist/operating-mode/types.d.ts.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -1
- package/package.json +5 -4
- package/src/cli/init.ts +43 -38
- package/dist/__integration__/fixtures/content-seeds.d.ts +0 -43
- package/dist/__integration__/fixtures/content-seeds.d.ts.map +0 -1
- package/dist/__integration__/fixtures/content-seeds.js +0 -99
- package/dist/__integration__/fixtures/content-seeds.js.map +0 -1
- package/dist/__integration__/fixtures/schemas.d.ts +0 -12
- package/dist/__integration__/fixtures/schemas.d.ts.map +0 -1
- package/dist/__integration__/fixtures/schemas.js +0 -65
- package/dist/__integration__/fixtures/schemas.js.map +0 -1
- package/dist/__integration__/test-utils/api-client.d.ts +0 -123
- package/dist/__integration__/test-utils/api-client.d.ts.map +0 -1
- package/dist/__integration__/test-utils/api-client.js +0 -118
- package/dist/__integration__/test-utils/api-client.js.map +0 -1
- package/dist/__integration__/test-utils/multi-user.d.ts +0 -25
- package/dist/__integration__/test-utils/multi-user.d.ts.map +0 -1
- package/dist/__integration__/test-utils/multi-user.js +0 -105
- package/dist/__integration__/test-utils/multi-user.js.map +0 -1
- package/dist/__integration__/test-utils/test-workspace.d.ts +0 -25
- package/dist/__integration__/test-utils/test-workspace.d.ts.map +0 -1
- package/dist/__integration__/test-utils/test-workspace.js +0 -102
- package/dist/__integration__/test-utils/test-workspace.js.map +0 -1
- package/dist/editor/BranchManager.stories.d.ts +0 -8
- package/dist/editor/BranchManager.stories.d.ts.map +0 -1
- package/dist/editor/BranchManager.stories.js +0 -74
- package/dist/editor/BranchManager.stories.js.map +0 -1
- package/dist/editor/CanopyEditor.stories.d.ts +0 -7
- package/dist/editor/CanopyEditor.stories.d.ts.map +0 -1
- package/dist/editor/CanopyEditor.stories.js +0 -99
- package/dist/editor/CanopyEditor.stories.js.map +0 -1
- package/dist/editor/CommentsPanel.stories.d.ts +0 -10
- package/dist/editor/CommentsPanel.stories.d.ts.map +0 -1
- package/dist/editor/CommentsPanel.stories.js +0 -175
- package/dist/editor/CommentsPanel.stories.js.map +0 -1
- package/dist/editor/Editor.stories.d.ts +0 -7
- package/dist/editor/Editor.stories.d.ts.map +0 -1
- package/dist/editor/Editor.stories.js +0 -95
- package/dist/editor/Editor.stories.js.map +0 -1
- package/dist/editor/EditorPanes.stories.d.ts +0 -7
- package/dist/editor/EditorPanes.stories.d.ts.map +0 -1
- package/dist/editor/EditorPanes.stories.js +0 -116
- package/dist/editor/EditorPanes.stories.js.map +0 -1
- package/dist/editor/EntryNavigator.stories.d.ts +0 -8
- package/dist/editor/EntryNavigator.stories.d.ts.map +0 -1
- package/dist/editor/EntryNavigator.stories.js +0 -42
- package/dist/editor/EntryNavigator.stories.js.map +0 -1
- package/dist/editor/FormRenderer.stories.d.ts +0 -7
- package/dist/editor/FormRenderer.stories.d.ts.map +0 -1
- package/dist/editor/FormRenderer.stories.js +0 -115
- package/dist/editor/FormRenderer.stories.js.map +0 -1
- package/dist/editor/GroupManager.stories.d.ts +0 -19
- package/dist/editor/GroupManager.stories.d.ts.map +0 -1
- package/dist/editor/GroupManager.stories.js +0 -265
- package/dist/editor/GroupManager.stories.js.map +0 -1
- package/dist/editor/PermissionManager.stories.d.ts +0 -20
- package/dist/editor/PermissionManager.stories.d.ts.map +0 -1
- package/dist/editor/PermissionManager.stories.js +0 -506
- package/dist/editor/PermissionManager.stories.js.map +0 -1
- package/dist/editor/comments/FieldWrapper.stories.d.ts +0 -10
- package/dist/editor/comments/FieldWrapper.stories.d.ts.map +0 -1
- package/dist/editor/comments/FieldWrapper.stories.js +0 -173
- package/dist/editor/comments/FieldWrapper.stories.js.map +0 -1
- package/dist/editor/fields/BlockField.stories.d.ts +0 -7
- package/dist/editor/fields/BlockField.stories.d.ts.map +0 -1
- package/dist/editor/fields/BlockField.stories.js +0 -50
- package/dist/editor/fields/BlockField.stories.js.map +0 -1
- package/dist/editor/fields/fields.stories.d.ts +0 -8
- package/dist/editor/fields/fields.stories.d.ts.map +0 -1
- package/dist/editor/fields/fields.stories.js +0 -34
- package/dist/editor/fields/fields.stories.js.map +0 -1
- package/dist/test-utils/api-test-helpers.d.ts +0 -238
- package/dist/test-utils/api-test-helpers.d.ts.map +0 -1
- package/dist/test-utils/api-test-helpers.js +0 -347
- package/dist/test-utils/api-test-helpers.js.map +0 -1
- package/dist/test-utils/console-spy.d.ts +0 -56
- package/dist/test-utils/console-spy.d.ts.map +0 -1
- package/dist/test-utils/console-spy.js +0 -81
- package/dist/test-utils/console-spy.js.map +0 -1
- package/dist/test-utils/git-helpers.d.ts +0 -21
- package/dist/test-utils/git-helpers.d.ts.map +0 -1
- package/dist/test-utils/git-helpers.js +0 -23
- package/dist/test-utils/git-helpers.js.map +0 -1
- package/dist/test-utils/index.d.ts +0 -5
- package/dist/test-utils/index.d.ts.map +0 -1
- package/dist/test-utils/index.js +0 -4
- package/dist/test-utils/index.js.map +0 -1
- package/src/__integration__/errors/invalid-content.test.ts +0 -238
- package/src/__integration__/errors/permission-denied.test.ts +0 -220
- package/src/__integration__/fixtures/content-seeds.ts +0 -105
- package/src/__integration__/fixtures/schemas.ts +0 -67
- package/src/__integration__/initialization/prod-sim-init.test.ts +0 -139
- package/src/__integration__/permissions/path-permissions.test.ts +0 -314
- package/src/__integration__/permissions/role-permissions.test.ts +0 -354
- package/src/__integration__/permissions/settings-branch-isolation.test.ts +0 -317
- package/src/__integration__/settings/groups-api.test.ts +0 -403
- package/src/__integration__/test-utils/api-client.ts +0 -167
- package/src/__integration__/test-utils/multi-user.ts +0 -129
- package/src/__integration__/test-utils/test-workspace.ts +0 -130
- package/src/__integration__/user/user-context.test.ts +0 -174
- package/src/__integration__/validation/input-validation.test.ts +0 -166
- package/src/__integration__/workflows/api-editing-workflow.test.ts +0 -244
- package/src/__integration__/workflows/conflict-resolution.test.ts +0 -259
- package/src/__integration__/workflows/editing-workflow.test.ts +0 -205
- package/src/__integration__/workflows/review-workflow.test.ts +0 -260
- package/src/ai/__tests__/build.integration.test.ts +0 -224
- package/src/ai/__tests__/generate.integration.test.ts +0 -495
- package/src/ai/__tests__/handler.integration.test.ts +0 -212
- package/src/ai/__tests__/json-to-markdown.test.ts +0 -553
- package/src/ai/generate.ts +0 -410
- package/src/ai/handler.ts +0 -123
- package/src/ai/index.ts +0 -26
- package/src/ai/json-to-markdown.ts +0 -424
- package/src/ai/resolve-branch.ts +0 -34
- package/src/ai/types.ts +0 -160
- package/src/api/AGENTS.md +0 -81
- package/src/api/__test__/mock-client.ts +0 -404
- package/src/api/assets.test.ts +0 -140
- package/src/api/assets.ts +0 -154
- package/src/api/branch-merge.test.ts +0 -163
- package/src/api/branch-merge.ts +0 -113
- package/src/api/branch-review.test.ts +0 -297
- package/src/api/branch-review.ts +0 -136
- package/src/api/branch-status.test.ts +0 -85
- package/src/api/branch-status.ts +0 -153
- package/src/api/branch-withdraw.test.ts +0 -146
- package/src/api/branch-withdraw.ts +0 -81
- package/src/api/branch-workflow.integration.test.ts +0 -578
- package/src/api/branch.test.ts +0 -620
- package/src/api/branch.ts +0 -492
- package/src/api/client.test.ts +0 -349
- package/src/api/client.ts +0 -506
- package/src/api/comments.test.ts +0 -285
- package/src/api/comments.ts +0 -210
- package/src/api/content.test.ts +0 -345
- package/src/api/content.ts +0 -454
- package/src/api/entries.test.ts +0 -1339
- package/src/api/entries.ts +0 -650
- package/src/api/github-sync.ts +0 -144
- package/src/api/groups.test.ts +0 -1013
- package/src/api/groups.ts +0 -375
- package/src/api/guards.test.ts +0 -533
- package/src/api/guards.ts +0 -271
- package/src/api/index.ts +0 -87
- package/src/api/permissions.test.ts +0 -766
- package/src/api/permissions.ts +0 -334
- package/src/api/reference-options.ts +0 -118
- package/src/api/resolve-references.ts +0 -107
- package/src/api/route-builder.ts +0 -289
- package/src/api/schema.test.ts +0 -840
- package/src/api/schema.ts +0 -936
- package/src/api/security.test.ts +0 -233
- package/src/api/settings-helpers.ts +0 -84
- package/src/api/types.ts +0 -40
- package/src/api/user.test.ts +0 -127
- package/src/api/user.ts +0 -42
- package/src/api/validators.test.ts +0 -275
- package/src/api/validators.ts +0 -176
- package/src/asset-store.test.ts +0 -37
- package/src/asset-store.ts +0 -110
- package/src/auth/cache.ts +0 -7
- package/src/auth/caching-auth-plugin.test.ts +0 -154
- package/src/auth/caching-auth-plugin.ts +0 -109
- package/src/auth/context-helpers.ts +0 -75
- package/src/auth/file-based-auth-cache.test.ts +0 -257
- package/src/auth/file-based-auth-cache.ts +0 -279
- package/src/auth/index.ts +0 -12
- package/src/auth/plugin.ts +0 -51
- package/src/auth/types.ts +0 -38
- package/src/authorization/__tests__/branch.test.ts +0 -260
- package/src/authorization/__tests__/content.test.ts +0 -142
- package/src/authorization/__tests__/path.test.ts +0 -133
- package/src/authorization/__tests__/permissions-loader.test.ts +0 -200
- package/src/authorization/branch.ts +0 -94
- package/src/authorization/content.ts +0 -93
- package/src/authorization/groups/index.ts +0 -11
- package/src/authorization/groups/loader.ts +0 -127
- package/src/authorization/groups/schema.ts +0 -48
- package/src/authorization/helpers.ts +0 -48
- package/src/authorization/index.ts +0 -84
- package/src/authorization/path.ts +0 -112
- package/src/authorization/permissions/index.ts +0 -11
- package/src/authorization/permissions/loader.ts +0 -116
- package/src/authorization/permissions/schema.ts +0 -66
- package/src/authorization/test-utils.ts +0 -15
- package/src/authorization/types.ts +0 -66
- package/src/authorization/validation.test.ts +0 -100
- package/src/authorization/validation.ts +0 -62
- package/src/branch-metadata.test.ts +0 -168
- package/src/branch-metadata.ts +0 -166
- package/src/branch-registry.test.ts +0 -248
- package/src/branch-registry.ts +0 -152
- package/src/branch-schema-cache.test.ts +0 -275
- package/src/branch-schema-cache.ts +0 -189
- package/src/branch-workspace.test.ts +0 -183
- package/src/branch-workspace.ts +0 -124
- package/src/build/generate-ai-content.ts +0 -78
- package/src/build/index.ts +0 -8
- package/src/build-mode.ts +0 -27
- package/src/cli/generate-ai-content.ts +0 -100
- package/src/cli/init.test.ts +0 -240
- package/src/cli/templates/canopy.ts.template +0 -55
- package/src/cli/templates.ts +0 -47
- package/src/client.ts +0 -12
- package/src/comment-store.test.ts +0 -442
- package/src/comment-store.ts +0 -301
- package/src/config/__tests__/config.test.ts +0 -513
- package/src/config/flatten.ts +0 -174
- package/src/config/helpers.ts +0 -167
- package/src/config/index.ts +0 -86
- package/src/config/schemas/collection.ts +0 -67
- package/src/config/schemas/config.ts +0 -77
- package/src/config/schemas/field.ts +0 -108
- package/src/config/schemas/media.ts +0 -27
- package/src/config/schemas/permissions.ts +0 -21
- package/src/config/types.ts +0 -321
- package/src/config/validation.ts +0 -70
- package/src/config-test.ts +0 -65
- package/src/config.ts +0 -11
- package/src/content-id-index.test.ts +0 -512
- package/src/content-id-index.ts +0 -479
- package/src/content-reader.test.ts +0 -478
- package/src/content-reader.ts +0 -214
- package/src/content-store.test.ts +0 -1126
- package/src/content-store.ts +0 -793
- package/src/context.ts +0 -111
- package/src/editor/BranchManager.stories.tsx +0 -80
- package/src/editor/BranchManager.test.tsx +0 -324
- package/src/editor/BranchManager.tsx +0 -461
- package/src/editor/CanopyEditor.stories.tsx +0 -128
- package/src/editor/CanopyEditor.test.tsx +0 -81
- package/src/editor/CanopyEditor.tsx +0 -73
- package/src/editor/CanopyEditorPage.test.tsx +0 -59
- package/src/editor/CanopyEditorPage.tsx +0 -25
- package/src/editor/CommentsPanel.stories.tsx +0 -184
- package/src/editor/CommentsPanel.tsx +0 -338
- package/src/editor/Editor.integration.test.tsx +0 -227
- package/src/editor/Editor.stories.tsx +0 -119
- package/src/editor/Editor.tsx +0 -1221
- package/src/editor/EditorPanes.stories.tsx +0 -256
- package/src/editor/EditorPanes.test.tsx +0 -77
- package/src/editor/EditorPanes.tsx +0 -180
- package/src/editor/EntryNavigator.stories.tsx +0 -65
- package/src/editor/EntryNavigator.test.tsx +0 -598
- package/src/editor/EntryNavigator.tsx +0 -665
- package/src/editor/FormRenderer.stories.tsx +0 -212
- package/src/editor/FormRenderer.test.tsx +0 -194
- package/src/editor/FormRenderer.tsx +0 -432
- package/src/editor/GroupManager.stories.tsx +0 -301
- package/src/editor/GroupManager.test.tsx +0 -682
- package/src/editor/GroupManager.tsx +0 -9
- package/src/editor/PermissionManager.stories.tsx +0 -539
- package/src/editor/PermissionManager.test.tsx +0 -864
- package/src/editor/PermissionManager.tsx +0 -12
- package/src/editor/canopy-path.test.ts +0 -23
- package/src/editor/canopy-path.ts +0 -52
- package/src/editor/client-reference-resolver.ts +0 -118
- package/src/editor/comments/BranchComments.tsx +0 -93
- package/src/editor/comments/EntryComments.tsx +0 -94
- package/src/editor/comments/FieldWrapper.stories.tsx +0 -210
- package/src/editor/comments/FieldWrapper.tsx +0 -129
- package/src/editor/comments/InlineCommentThread.test.tsx +0 -384
- package/src/editor/comments/InlineCommentThread.tsx +0 -246
- package/src/editor/comments/ThreadCarousel.test.tsx +0 -393
- package/src/editor/comments/ThreadCarousel.tsx +0 -525
- package/src/editor/components/ConfirmDeleteModal.tsx +0 -49
- package/src/editor/components/EditorContext.tsx +0 -49
- package/src/editor/components/EditorFooter.tsx +0 -47
- package/src/editor/components/EditorHeader.tsx +0 -492
- package/src/editor/components/EditorSidebar.tsx +0 -193
- package/src/editor/components/EntryCreateModal.tsx +0 -193
- package/src/editor/components/RenameEntryModal.tsx +0 -152
- package/src/editor/components/UserBadge.test.tsx +0 -274
- package/src/editor/components/UserBadge.tsx +0 -240
- package/src/editor/components/index.ts +0 -6
- package/src/editor/context/ApiClientContext.tsx +0 -56
- package/src/editor/context/EditorStateContext.tsx +0 -221
- package/src/editor/context/index.ts +0 -40
- package/src/editor/editor-config.test.ts +0 -385
- package/src/editor/editor-config.ts +0 -94
- package/src/editor/editor-utils.test.ts +0 -772
- package/src/editor/editor-utils.ts +0 -303
- package/src/editor/env.ts +0 -4
- package/src/editor/fields/BlockField.stories.tsx +0 -79
- package/src/editor/fields/BlockField.tsx +0 -267
- package/src/editor/fields/CodeField.tsx +0 -41
- package/src/editor/fields/MarkdownField.tsx +0 -205
- package/src/editor/fields/ObjectField.tsx +0 -71
- package/src/editor/fields/ReferenceField.tsx +0 -138
- package/src/editor/fields/SelectField.tsx +0 -76
- package/src/editor/fields/TextField.tsx +0 -35
- package/src/editor/fields/ToggleField.tsx +0 -37
- package/src/editor/fields/fields.stories.tsx +0 -40
- package/src/editor/group-manager/ExternalGroupsTab.tsx +0 -114
- package/src/editor/group-manager/GroupCard.tsx +0 -102
- package/src/editor/group-manager/GroupForm.tsx +0 -66
- package/src/editor/group-manager/InternalGroupsTab.tsx +0 -147
- package/src/editor/group-manager/MemberList.tsx +0 -184
- package/src/editor/group-manager/hooks/useExternalGroupSearch.ts +0 -63
- package/src/editor/group-manager/hooks/useGroupState.ts +0 -134
- package/src/editor/group-manager/hooks/useUserSearch.ts +0 -84
- package/src/editor/group-manager/index.tsx +0 -210
- package/src/editor/group-manager/types.ts +0 -28
- package/src/editor/hooks/README.md +0 -26
- package/src/editor/hooks/__test__/test-utils.tsx +0 -183
- package/src/editor/hooks/index.ts +0 -23
- package/src/editor/hooks/useBranchActions.test.tsx +0 -267
- package/src/editor/hooks/useBranchActions.tsx +0 -121
- package/src/editor/hooks/useBranchManager.test.tsx +0 -391
- package/src/editor/hooks/useBranchManager.tsx +0 -326
- package/src/editor/hooks/useCommentSystem.test.ts +0 -615
- package/src/editor/hooks/useCommentSystem.ts +0 -347
- package/src/editor/hooks/useDraftManager.test.ts +0 -375
- package/src/editor/hooks/useDraftManager.ts +0 -259
- package/src/editor/hooks/useEditorLayout.test.ts +0 -147
- package/src/editor/hooks/useEditorLayout.ts +0 -67
- package/src/editor/hooks/useEntryManager.test.ts +0 -588
- package/src/editor/hooks/useEntryManager.ts +0 -387
- package/src/editor/hooks/useGroupManager.test.ts +0 -277
- package/src/editor/hooks/useGroupManager.ts +0 -139
- package/src/editor/hooks/usePermissionManager.test.ts +0 -211
- package/src/editor/hooks/usePermissionManager.ts +0 -113
- package/src/editor/hooks/useReferenceResolution.ts +0 -248
- package/src/editor/hooks/useSchemaManager.test.ts +0 -370
- package/src/editor/hooks/useSchemaManager.ts +0 -310
- package/src/editor/hooks/useUserContext.tsx +0 -57
- package/src/editor/hooks/useUserMetadata.test.ts +0 -191
- package/src/editor/hooks/useUserMetadata.ts +0 -71
- package/src/editor/permission-manager/GroupSelector.tsx +0 -73
- package/src/editor/permission-manager/PermissionEditor.tsx +0 -321
- package/src/editor/permission-manager/PermissionLevelBadge.tsx +0 -53
- package/src/editor/permission-manager/PermissionTree.tsx +0 -237
- package/src/editor/permission-manager/UserSelector.tsx +0 -95
- package/src/editor/permission-manager/constants.tsx +0 -18
- package/src/editor/permission-manager/hooks/useGroupsAndUsers.ts +0 -153
- package/src/editor/permission-manager/hooks/usePermissionTree.ts +0 -200
- package/src/editor/permission-manager/index.tsx +0 -294
- package/src/editor/permission-manager/types.ts +0 -58
- package/src/editor/permission-manager/utils.ts +0 -179
- package/src/editor/preview-bridge.test.tsx +0 -50
- package/src/editor/preview-bridge.tsx +0 -294
- package/src/editor/schema-editor/CollectionEditor.test.tsx +0 -238
- package/src/editor/schema-editor/CollectionEditor.tsx +0 -520
- package/src/editor/schema-editor/EntryTypeEditor.test.tsx +0 -215
- package/src/editor/schema-editor/EntryTypeEditor.tsx +0 -367
- package/src/editor/schema-editor/index.ts +0 -19
- package/src/editor/setup-test-dom.ts +0 -10
- package/src/editor/test-setup.ts +0 -33
- package/src/editor/theme.tsx +0 -119
- package/src/editor/utils/env.ts +0 -39
- package/src/entry-schema-registry.test.ts +0 -281
- package/src/entry-schema-registry.ts +0 -121
- package/src/entry-schema.ts +0 -84
- package/src/git-manager.test.ts +0 -552
- package/src/git-manager.ts +0 -667
- package/src/github-service.test.ts +0 -312
- package/src/github-service.ts +0 -295
- package/src/http/handler.test.ts +0 -275
- package/src/http/handler.ts +0 -280
- package/src/http/index.ts +0 -11
- package/src/http/router.ts +0 -164
- package/src/http/types.ts +0 -44
- package/src/id.test.ts +0 -48
- package/src/id.ts +0 -22
- package/src/index.ts +0 -26
- package/src/operating-mode/__tests__/strategies.test.ts +0 -511
- package/src/operating-mode/client-safe-strategy.ts +0 -184
- package/src/operating-mode/client-unsafe-strategy.ts +0 -303
- package/src/operating-mode/client.ts +0 -13
- package/src/operating-mode/index.ts +0 -34
- package/src/operating-mode/types.ts +0 -186
- package/src/paths/__tests__/branch.test.ts +0 -53
- package/src/paths/__tests__/normalize.test.ts +0 -141
- package/src/paths/__tests__/resolve.test.ts +0 -207
- package/src/paths/__tests__/validation.test.ts +0 -61
- package/src/paths/branch.ts +0 -115
- package/src/paths/index.ts +0 -73
- package/src/paths/normalize-server.ts +0 -40
- package/src/paths/normalize.ts +0 -107
- package/src/paths/resolve.ts +0 -61
- package/src/paths/test-utils.ts +0 -37
- package/src/paths/types.ts +0 -68
- package/src/paths/validation.test.ts +0 -480
- package/src/paths/validation.ts +0 -391
- package/src/reference-resolver.test.ts +0 -107
- package/src/reference-resolver.ts +0 -157
- package/src/schema/index.ts +0 -29
- package/src/schema/meta-loader.ts +0 -366
- package/src/schema/resolver.ts +0 -83
- package/src/schema/schema-store-types.ts +0 -56
- package/src/schema/schema-store.test.ts +0 -816
- package/src/schema/schema-store.ts +0 -795
- package/src/schema/types.ts +0 -33
- package/src/schema-meta-loader.test.ts +0 -447
- package/src/server.ts +0 -15
- package/src/services.test.ts +0 -559
- package/src/services.ts +0 -373
- package/src/settings-branch-utils.ts +0 -53
- package/src/settings-workspace.ts +0 -156
- package/src/task-queue/README.md +0 -144
- package/src/task-queue/index.ts +0 -14
- package/src/task-queue/task-queue.test.ts +0 -524
- package/src/task-queue/task-queue.ts +0 -514
- package/src/task-queue/types.ts +0 -41
- package/src/test-utils/api-test-helpers.ts +0 -445
- package/src/test-utils/console-spy.test.ts +0 -14
- package/src/test-utils/console-spy.ts +0 -125
- package/src/test-utils/git-helpers.ts +0 -31
- package/src/test-utils/index.ts +0 -4
- package/src/types.ts +0 -54
- package/src/user.ts +0 -118
- package/src/utils/debug.test.ts +0 -114
- package/src/utils/debug.ts +0 -127
- package/src/utils/error.test.ts +0 -92
- package/src/utils/error.ts +0 -83
- package/src/utils/format.ts +0 -12
- package/src/validation/__tests__/field-traversal.test.ts +0 -263
- package/src/validation/deletion-checker.ts +0 -234
- package/src/validation/field-traversal.ts +0 -146
- package/src/validation/reference-validator.ts +0 -168
- package/src/worker/cms-worker-rebase.test.ts +0 -473
- package/src/worker/cms-worker.ts +0 -777
- package/src/worker/integration.test.ts +0 -289
- package/src/worker/task-queue-config.ts +0 -25
- package/src/worker/task-queue.test.ts +0 -452
- package/src/worker/task-queue.ts +0 -58
- /package/{src/cli/templates → dist/cli/template-files}/Dockerfile.cms.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/canopycms.config.ts.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/deploy-cms.yml.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/edit-page.tsx.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/route.ts.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/schemas.ts.template +0 -0
package/src/git-manager.test.ts
DELETED
|
@@ -1,552 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises'
|
|
2
|
-
import os from 'node:os'
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
|
|
5
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
6
|
-
import { simpleGit } from 'simple-git'
|
|
7
|
-
|
|
8
|
-
import { GitManager } from './git-manager'
|
|
9
|
-
import { initTestRepo } from './test-utils'
|
|
10
|
-
|
|
11
|
-
describe('GitManager.ensureLocalSimulatedRemote', () => {
|
|
12
|
-
let tmpDir: string
|
|
13
|
-
|
|
14
|
-
beforeEach(async () => {
|
|
15
|
-
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'canopy-git-test-'))
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
afterEach(async () => {
|
|
19
|
-
await fs.rm(tmpDir, { recursive: true, force: true })
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
it('creates bare remote and pushes baseBranch when remote does not exist', async () => {
|
|
23
|
-
// Setup: create a git repo with a commit on main
|
|
24
|
-
const git = await initTestRepo(tmpDir)
|
|
25
|
-
await git.raw(['branch', '-M', 'main'])
|
|
26
|
-
await fs.writeFile(path.join(tmpDir, 'test.txt'), 'hello', 'utf8')
|
|
27
|
-
await git.add(['.'])
|
|
28
|
-
await git.commit('initial commit')
|
|
29
|
-
|
|
30
|
-
const remotePath = path.join(tmpDir, 'remote.git')
|
|
31
|
-
|
|
32
|
-
// Act
|
|
33
|
-
await GitManager.ensureLocalSimulatedRemote({
|
|
34
|
-
remotePath,
|
|
35
|
-
sourcePath: tmpDir,
|
|
36
|
-
baseBranch: 'main',
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
// Assert: remote exists and has main branch
|
|
40
|
-
const remoteStat = await fs.stat(remotePath)
|
|
41
|
-
expect(remoteStat.isDirectory()).toBe(true)
|
|
42
|
-
|
|
43
|
-
const remoteGit = simpleGit({ baseDir: remotePath })
|
|
44
|
-
const branches = await remoteGit.branch()
|
|
45
|
-
expect(branches.all).toContain('main')
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('is idempotent - does not recreate if remote already exists', async () => {
|
|
49
|
-
// Setup
|
|
50
|
-
const git = simpleGit({ baseDir: tmpDir })
|
|
51
|
-
await git.init()
|
|
52
|
-
await git.raw(['branch', '-M', 'main'])
|
|
53
|
-
await fs.writeFile(path.join(tmpDir, 'test.txt'), 'hello', 'utf8')
|
|
54
|
-
await git.add(['.'])
|
|
55
|
-
await git.commit('initial commit')
|
|
56
|
-
|
|
57
|
-
const remotePath = path.join(tmpDir, 'remote.git')
|
|
58
|
-
|
|
59
|
-
// Create remote first time
|
|
60
|
-
await GitManager.ensureLocalSimulatedRemote({
|
|
61
|
-
remotePath,
|
|
62
|
-
sourcePath: tmpDir,
|
|
63
|
-
baseBranch: 'main',
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
// Get initial state
|
|
67
|
-
const initialStat = await fs.stat(remotePath)
|
|
68
|
-
const initialMtime = initialStat.mtimeMs
|
|
69
|
-
|
|
70
|
-
// Wait a bit to ensure mtime would change if recreated
|
|
71
|
-
await new Promise((resolve) => setTimeout(resolve, 10))
|
|
72
|
-
|
|
73
|
-
// Act: call again
|
|
74
|
-
await GitManager.ensureLocalSimulatedRemote({
|
|
75
|
-
remotePath,
|
|
76
|
-
sourcePath: tmpDir,
|
|
77
|
-
baseBranch: 'main',
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
// Assert: directory wasn't recreated (mtime unchanged)
|
|
81
|
-
const finalStat = await fs.stat(remotePath)
|
|
82
|
-
expect(finalStat.mtimeMs).toBe(initialMtime)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('throws error if sourcePath is not a git repo', async () => {
|
|
86
|
-
const remotePath = path.join(tmpDir, 'remote.git')
|
|
87
|
-
|
|
88
|
-
await expect(
|
|
89
|
-
GitManager.ensureLocalSimulatedRemote({
|
|
90
|
-
remotePath,
|
|
91
|
-
sourcePath: tmpDir,
|
|
92
|
-
baseBranch: 'main',
|
|
93
|
-
}),
|
|
94
|
-
).rejects.toThrow('not a git repository')
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('throws error if git repo has no commits', async () => {
|
|
98
|
-
// Setup: init repo but don't commit
|
|
99
|
-
const git = simpleGit({ baseDir: tmpDir })
|
|
100
|
-
await git.init()
|
|
101
|
-
|
|
102
|
-
const remotePath = path.join(tmpDir, 'remote.git')
|
|
103
|
-
|
|
104
|
-
await expect(
|
|
105
|
-
GitManager.ensureLocalSimulatedRemote({
|
|
106
|
-
remotePath,
|
|
107
|
-
sourcePath: tmpDir,
|
|
108
|
-
baseBranch: 'main',
|
|
109
|
-
}),
|
|
110
|
-
).rejects.toThrow('repository has no commits')
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('throws error if baseBranch does not exist locally', async () => {
|
|
114
|
-
// Setup: create repo with commit on main, but ask for develop
|
|
115
|
-
const git = simpleGit({ baseDir: tmpDir })
|
|
116
|
-
await git.init()
|
|
117
|
-
await git.raw(['branch', '-M', 'main'])
|
|
118
|
-
await fs.writeFile(path.join(tmpDir, 'test.txt'), 'hello', 'utf8')
|
|
119
|
-
await git.add(['.'])
|
|
120
|
-
await git.commit('initial commit')
|
|
121
|
-
|
|
122
|
-
const remotePath = path.join(tmpDir, 'remote.git')
|
|
123
|
-
|
|
124
|
-
await expect(
|
|
125
|
-
GitManager.ensureLocalSimulatedRemote({
|
|
126
|
-
remotePath,
|
|
127
|
-
sourcePath: tmpDir,
|
|
128
|
-
baseBranch: 'develop',
|
|
129
|
-
}),
|
|
130
|
-
).rejects.toThrow("base branch 'develop' does not exist locally")
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('pushes actual baseBranch content, not current HEAD', async () => {
|
|
134
|
-
// Setup: create main with one commit, then feature branch with different commit
|
|
135
|
-
const git = await initTestRepo(tmpDir)
|
|
136
|
-
await git.raw(['branch', '-M', 'main'])
|
|
137
|
-
await fs.writeFile(path.join(tmpDir, 'main.txt'), 'main content', 'utf8')
|
|
138
|
-
await git.add(['.'])
|
|
139
|
-
await git.commit('main commit')
|
|
140
|
-
|
|
141
|
-
// Create feature branch with different content
|
|
142
|
-
await git.checkoutLocalBranch('feature')
|
|
143
|
-
await fs.writeFile(path.join(tmpDir, 'feature.txt'), 'feature content', 'utf8')
|
|
144
|
-
await git.add(['.'])
|
|
145
|
-
await git.commit('feature commit')
|
|
146
|
-
|
|
147
|
-
const remotePath = path.join(tmpDir, 'remote.git')
|
|
148
|
-
|
|
149
|
-
// Act: initialize remote while on feature branch, but specify main as baseBranch
|
|
150
|
-
await GitManager.ensureLocalSimulatedRemote({
|
|
151
|
-
remotePath,
|
|
152
|
-
sourcePath: tmpDir,
|
|
153
|
-
baseBranch: 'main',
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
// Assert: remote has main, not feature
|
|
157
|
-
const remoteGit = simpleGit({ baseDir: remotePath })
|
|
158
|
-
const branches = await remoteGit.branch()
|
|
159
|
-
expect(branches.all).toContain('main')
|
|
160
|
-
expect(branches.all).not.toContain('feature')
|
|
161
|
-
|
|
162
|
-
// Clone the remote to verify content
|
|
163
|
-
const clonePath = path.join(tmpDir, 'clone')
|
|
164
|
-
await simpleGit().clone(remotePath, clonePath)
|
|
165
|
-
const cloneFiles = await fs.readdir(clonePath)
|
|
166
|
-
expect(cloneFiles).toContain('main.txt')
|
|
167
|
-
expect(cloneFiles).not.toContain('feature.txt')
|
|
168
|
-
})
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
describe('GitManager.resolveRemoteUrl', () => {
|
|
172
|
-
let tmpDir: string
|
|
173
|
-
let originalEnv: string | undefined
|
|
174
|
-
|
|
175
|
-
beforeEach(async () => {
|
|
176
|
-
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'canopy-resolve-test-'))
|
|
177
|
-
originalEnv = process.env.CANOPYCMS_REMOTE_URL
|
|
178
|
-
delete process.env.CANOPYCMS_REMOTE_URL
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
afterEach(async () => {
|
|
182
|
-
await fs.rm(tmpDir, { recursive: true, force: true })
|
|
183
|
-
if (originalEnv !== undefined) {
|
|
184
|
-
process.env.CANOPYCMS_REMOTE_URL = originalEnv
|
|
185
|
-
} else {
|
|
186
|
-
delete process.env.CANOPYCMS_REMOTE_URL
|
|
187
|
-
}
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
it('returns explicit remoteUrl when provided (highest priority)', async () => {
|
|
191
|
-
const result = await GitManager.resolveRemoteUrl({
|
|
192
|
-
mode: 'prod-sim',
|
|
193
|
-
remoteUrl: 'https://explicit.com/repo.git',
|
|
194
|
-
defaultRemoteUrl: 'https://default.com/repo.git',
|
|
195
|
-
baseBranch: 'main',
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
expect(result).toBe('https://explicit.com/repo.git')
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
it('returns defaultRemoteUrl when no explicit url', async () => {
|
|
202
|
-
const result = await GitManager.resolveRemoteUrl({
|
|
203
|
-
mode: 'prod-sim',
|
|
204
|
-
defaultRemoteUrl: 'https://default.com/repo.git',
|
|
205
|
-
baseBranch: 'main',
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
expect(result).toBe('https://default.com/repo.git')
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
it('returns env var CANOPYCMS_REMOTE_URL when no config', async () => {
|
|
212
|
-
process.env.CANOPYCMS_REMOTE_URL = 'https://env.com/repo.git'
|
|
213
|
-
|
|
214
|
-
const result = await GitManager.resolveRemoteUrl({
|
|
215
|
-
mode: 'prod-sim',
|
|
216
|
-
baseBranch: 'main',
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
expect(result).toBe('https://env.com/repo.git')
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
it('auto-initializes and returns local remote path for prod-sim', async () => {
|
|
223
|
-
// Setup: create git repo in tmpDir with commit
|
|
224
|
-
const git = simpleGit({ baseDir: tmpDir })
|
|
225
|
-
await git.init()
|
|
226
|
-
await git.raw(['branch', '-M', 'main'])
|
|
227
|
-
await fs.writeFile(path.join(tmpDir, 'test.txt'), 'hello', 'utf8')
|
|
228
|
-
await git.add(['.'])
|
|
229
|
-
await git.commit('initial commit')
|
|
230
|
-
|
|
231
|
-
// Get the real git root path (handles symlinks on macOS)
|
|
232
|
-
const gitRootResult = await git.raw(['rev-parse', '--show-toplevel'])
|
|
233
|
-
const gitRoot = gitRootResult.trim()
|
|
234
|
-
|
|
235
|
-
// Mock process.cwd() to return tmpDir
|
|
236
|
-
const cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue(tmpDir)
|
|
237
|
-
|
|
238
|
-
try {
|
|
239
|
-
const result = await GitManager.resolveRemoteUrl({
|
|
240
|
-
mode: 'prod-sim',
|
|
241
|
-
baseBranch: 'main',
|
|
242
|
-
})
|
|
243
|
-
|
|
244
|
-
expect(result).toBe(path.join(gitRoot, '.canopy-prod-sim/remote.git'))
|
|
245
|
-
|
|
246
|
-
// Verify remote was created
|
|
247
|
-
const remoteStat = await fs.stat(path.join(gitRoot, '.canopy-prod-sim/remote.git'))
|
|
248
|
-
expect(remoteStat.isDirectory()).toBe(true)
|
|
249
|
-
} finally {
|
|
250
|
-
cwdSpy.mockRestore()
|
|
251
|
-
}
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
it('returns undefined for dev mode', async () => {
|
|
255
|
-
const result = await GitManager.resolveRemoteUrl({
|
|
256
|
-
mode: 'dev',
|
|
257
|
-
baseBranch: 'main',
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
expect(result).toBeUndefined()
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
it('skips auto-init when explicit remoteUrl provided', async () => {
|
|
264
|
-
const cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue(tmpDir)
|
|
265
|
-
|
|
266
|
-
try {
|
|
267
|
-
const result = await GitManager.resolveRemoteUrl({
|
|
268
|
-
mode: 'prod-sim',
|
|
269
|
-
remoteUrl: 'https://explicit.com/repo.git',
|
|
270
|
-
baseBranch: 'main',
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
expect(result).toBe('https://explicit.com/repo.git')
|
|
274
|
-
|
|
275
|
-
// Verify no local remote was created
|
|
276
|
-
await expect(fs.stat(path.join(tmpDir, '.canopycms/remote.git'))).rejects.toThrow()
|
|
277
|
-
} finally {
|
|
278
|
-
cwdSpy.mockRestore()
|
|
279
|
-
}
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
it('uses sourceRoot when provided for prod-sim', async () => {
|
|
283
|
-
// Setup: create git repo with subdirectory structure
|
|
284
|
-
const git = await initTestRepo(tmpDir)
|
|
285
|
-
await git.raw(['branch', '-M', 'main'])
|
|
286
|
-
|
|
287
|
-
// Create subdirectory with content
|
|
288
|
-
const subdir = path.join(tmpDir, 'packages/example')
|
|
289
|
-
await fs.mkdir(subdir, { recursive: true })
|
|
290
|
-
await fs.writeFile(path.join(subdir, 'test.txt'), 'hello', 'utf8')
|
|
291
|
-
await git.add(['.'])
|
|
292
|
-
await git.commit('initial commit')
|
|
293
|
-
|
|
294
|
-
// Get the real git root path (handles symlinks on macOS)
|
|
295
|
-
const gitRootResult = await git.raw(['rev-parse', '--show-toplevel'])
|
|
296
|
-
const gitRoot = gitRootResult.trim()
|
|
297
|
-
|
|
298
|
-
// Mock process.cwd() to return tmpDir (git root)
|
|
299
|
-
const cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue(tmpDir)
|
|
300
|
-
|
|
301
|
-
try {
|
|
302
|
-
const result = await GitManager.resolveRemoteUrl({
|
|
303
|
-
mode: 'prod-sim',
|
|
304
|
-
baseBranch: 'main',
|
|
305
|
-
sourceRoot: 'packages/example',
|
|
306
|
-
})
|
|
307
|
-
|
|
308
|
-
// Should resolve to the subdirectory (using real git root path)
|
|
309
|
-
expect(result).toBe(path.join(gitRoot, 'packages/example/.canopy-prod-sim/remote.git'))
|
|
310
|
-
|
|
311
|
-
// Verify remote was created in the subdirectory
|
|
312
|
-
const actualSubdir = path.join(gitRoot, 'packages/example')
|
|
313
|
-
const remoteStat = await fs.stat(path.join(actualSubdir, '.canopy-prod-sim/remote.git'))
|
|
314
|
-
expect(remoteStat.isDirectory()).toBe(true)
|
|
315
|
-
|
|
316
|
-
// Verify remote contains main branch
|
|
317
|
-
const remoteGit = simpleGit({
|
|
318
|
-
baseDir: path.join(actualSubdir, '.canopy-prod-sim/remote.git'),
|
|
319
|
-
})
|
|
320
|
-
const branches = await remoteGit.branch()
|
|
321
|
-
expect(branches.all).toContain('main')
|
|
322
|
-
|
|
323
|
-
// Clone and verify only subdirectory content was pushed (via git subtree)
|
|
324
|
-
const clonePath = path.join(tmpDir, 'clone-test')
|
|
325
|
-
await simpleGit().clone(path.join(actualSubdir, '.canopy-prod-sim/remote.git'), clonePath)
|
|
326
|
-
const cloneFiles = await fs.readdir(clonePath)
|
|
327
|
-
expect(cloneFiles).toContain('test.txt')
|
|
328
|
-
// Should NOT contain packages/ dir since we used git subtree split
|
|
329
|
-
expect(cloneFiles).not.toContain('packages')
|
|
330
|
-
} finally {
|
|
331
|
-
cwdSpy.mockRestore()
|
|
332
|
-
}
|
|
333
|
-
})
|
|
334
|
-
it('auto-detects remote.git at workspace root in prod mode', async () => {
|
|
335
|
-
// Setup: create a bare repo at the expected workspace path
|
|
336
|
-
const workspaceRoot = path.join(tmpDir, 'workspace')
|
|
337
|
-
const remoteGitPath = path.join(workspaceRoot, 'remote.git')
|
|
338
|
-
await fs.mkdir(workspaceRoot, { recursive: true })
|
|
339
|
-
const bareGit = simpleGit()
|
|
340
|
-
await bareGit
|
|
341
|
-
.clone(tmpDir, remoteGitPath, ['--bare']) // needs a source, use tmpDir as dummy
|
|
342
|
-
.catch(async () => {
|
|
343
|
-
// If tmpDir isn't a repo, just init a bare repo directly
|
|
344
|
-
await fs.mkdir(remoteGitPath, { recursive: true })
|
|
345
|
-
await simpleGit({ baseDir: remoteGitPath }).init(true)
|
|
346
|
-
})
|
|
347
|
-
|
|
348
|
-
// Point CANOPYCMS_WORKSPACE_ROOT to our test workspace
|
|
349
|
-
const origWorkspace = process.env.CANOPYCMS_WORKSPACE_ROOT
|
|
350
|
-
process.env.CANOPYCMS_WORKSPACE_ROOT = workspaceRoot
|
|
351
|
-
|
|
352
|
-
try {
|
|
353
|
-
// Clear strategy cache so it picks up new env var
|
|
354
|
-
const { clearStrategyCache } = await import('./operating-mode/client-unsafe-strategy')
|
|
355
|
-
clearStrategyCache()
|
|
356
|
-
|
|
357
|
-
const result = await GitManager.resolveRemoteUrl({
|
|
358
|
-
mode: 'prod',
|
|
359
|
-
baseBranch: 'main',
|
|
360
|
-
})
|
|
361
|
-
|
|
362
|
-
expect(result).toBe(remoteGitPath)
|
|
363
|
-
} finally {
|
|
364
|
-
if (origWorkspace !== undefined) {
|
|
365
|
-
process.env.CANOPYCMS_WORKSPACE_ROOT = origWorkspace
|
|
366
|
-
} else {
|
|
367
|
-
delete process.env.CANOPYCMS_WORKSPACE_ROOT
|
|
368
|
-
}
|
|
369
|
-
const { clearStrategyCache } = await import('./operating-mode/client-unsafe-strategy')
|
|
370
|
-
clearStrategyCache()
|
|
371
|
-
}
|
|
372
|
-
})
|
|
373
|
-
|
|
374
|
-
it('returns undefined for prod mode when remote.git does not exist', async () => {
|
|
375
|
-
// Point CANOPYCMS_WORKSPACE_ROOT to a directory without remote.git
|
|
376
|
-
const workspaceRoot = path.join(tmpDir, 'empty-workspace')
|
|
377
|
-
await fs.mkdir(workspaceRoot, { recursive: true })
|
|
378
|
-
|
|
379
|
-
const origWorkspace = process.env.CANOPYCMS_WORKSPACE_ROOT
|
|
380
|
-
process.env.CANOPYCMS_WORKSPACE_ROOT = workspaceRoot
|
|
381
|
-
|
|
382
|
-
try {
|
|
383
|
-
const { clearStrategyCache } = await import('./operating-mode/client-unsafe-strategy')
|
|
384
|
-
clearStrategyCache()
|
|
385
|
-
|
|
386
|
-
const result = await GitManager.resolveRemoteUrl({
|
|
387
|
-
mode: 'prod',
|
|
388
|
-
baseBranch: 'main',
|
|
389
|
-
})
|
|
390
|
-
|
|
391
|
-
expect(result).toBeUndefined()
|
|
392
|
-
} finally {
|
|
393
|
-
if (origWorkspace !== undefined) {
|
|
394
|
-
process.env.CANOPYCMS_WORKSPACE_ROOT = origWorkspace
|
|
395
|
-
} else {
|
|
396
|
-
delete process.env.CANOPYCMS_WORKSPACE_ROOT
|
|
397
|
-
}
|
|
398
|
-
const { clearStrategyCache } = await import('./operating-mode/client-unsafe-strategy')
|
|
399
|
-
clearStrategyCache()
|
|
400
|
-
}
|
|
401
|
-
})
|
|
402
|
-
|
|
403
|
-
it('explicit remoteUrl takes priority over auto-detected remote.git in prod mode', async () => {
|
|
404
|
-
// Setup: create remote.git at workspace root
|
|
405
|
-
const workspaceRoot = path.join(tmpDir, 'workspace')
|
|
406
|
-
const remoteGitPath = path.join(workspaceRoot, 'remote.git')
|
|
407
|
-
await fs.mkdir(remoteGitPath, { recursive: true })
|
|
408
|
-
await simpleGit({ baseDir: remoteGitPath }).init(true)
|
|
409
|
-
|
|
410
|
-
const origWorkspace = process.env.CANOPYCMS_WORKSPACE_ROOT
|
|
411
|
-
process.env.CANOPYCMS_WORKSPACE_ROOT = workspaceRoot
|
|
412
|
-
|
|
413
|
-
try {
|
|
414
|
-
const { clearStrategyCache } = await import('./operating-mode/client-unsafe-strategy')
|
|
415
|
-
clearStrategyCache()
|
|
416
|
-
|
|
417
|
-
const result = await GitManager.resolveRemoteUrl({
|
|
418
|
-
mode: 'prod',
|
|
419
|
-
remoteUrl: 'https://explicit.com/repo.git',
|
|
420
|
-
baseBranch: 'main',
|
|
421
|
-
})
|
|
422
|
-
|
|
423
|
-
// Explicit URL should win over auto-detected path
|
|
424
|
-
expect(result).toBe('https://explicit.com/repo.git')
|
|
425
|
-
} finally {
|
|
426
|
-
if (origWorkspace !== undefined) {
|
|
427
|
-
process.env.CANOPYCMS_WORKSPACE_ROOT = origWorkspace
|
|
428
|
-
} else {
|
|
429
|
-
delete process.env.CANOPYCMS_WORKSPACE_ROOT
|
|
430
|
-
}
|
|
431
|
-
const { clearStrategyCache } = await import('./operating-mode/client-unsafe-strategy')
|
|
432
|
-
clearStrategyCache()
|
|
433
|
-
}
|
|
434
|
-
})
|
|
435
|
-
|
|
436
|
-
it('env var CANOPYCMS_REMOTE_URL takes priority over auto-detected remote.git', async () => {
|
|
437
|
-
// Setup: create remote.git at workspace root
|
|
438
|
-
const workspaceRoot = path.join(tmpDir, 'workspace')
|
|
439
|
-
const remoteGitPath = path.join(workspaceRoot, 'remote.git')
|
|
440
|
-
await fs.mkdir(remoteGitPath, { recursive: true })
|
|
441
|
-
await simpleGit({ baseDir: remoteGitPath }).init(true)
|
|
442
|
-
|
|
443
|
-
const origWorkspace = process.env.CANOPYCMS_WORKSPACE_ROOT
|
|
444
|
-
process.env.CANOPYCMS_WORKSPACE_ROOT = workspaceRoot
|
|
445
|
-
process.env.CANOPYCMS_REMOTE_URL = 'https://env.com/repo.git'
|
|
446
|
-
|
|
447
|
-
try {
|
|
448
|
-
const { clearStrategyCache } = await import('./operating-mode/client-unsafe-strategy')
|
|
449
|
-
clearStrategyCache()
|
|
450
|
-
|
|
451
|
-
const result = await GitManager.resolveRemoteUrl({
|
|
452
|
-
mode: 'prod',
|
|
453
|
-
baseBranch: 'main',
|
|
454
|
-
})
|
|
455
|
-
|
|
456
|
-
// Env var should win over auto-detected path
|
|
457
|
-
expect(result).toBe('https://env.com/repo.git')
|
|
458
|
-
} finally {
|
|
459
|
-
if (origWorkspace !== undefined) {
|
|
460
|
-
process.env.CANOPYCMS_WORKSPACE_ROOT = origWorkspace
|
|
461
|
-
} else {
|
|
462
|
-
delete process.env.CANOPYCMS_WORKSPACE_ROOT
|
|
463
|
-
}
|
|
464
|
-
const { clearStrategyCache } = await import('./operating-mode/client-unsafe-strategy')
|
|
465
|
-
clearStrategyCache()
|
|
466
|
-
}
|
|
467
|
-
})
|
|
468
|
-
}, 10000)
|
|
469
|
-
|
|
470
|
-
describe('GitManager.ensureAuthor', () => {
|
|
471
|
-
let tmpDir: string
|
|
472
|
-
|
|
473
|
-
beforeEach(async () => {
|
|
474
|
-
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'canopy-git-test-'))
|
|
475
|
-
})
|
|
476
|
-
|
|
477
|
-
afterEach(async () => {
|
|
478
|
-
await fs.rm(tmpDir, { recursive: true, force: true })
|
|
479
|
-
})
|
|
480
|
-
|
|
481
|
-
it('allows setting author in managed repository', async () => {
|
|
482
|
-
// Setup: create managed repo
|
|
483
|
-
const git = await initTestRepo(tmpDir)
|
|
484
|
-
await git.raw(['branch', '-M', 'main'])
|
|
485
|
-
await fs.writeFile(path.join(tmpDir, 'test.txt'), 'content', 'utf8')
|
|
486
|
-
await git.add(['.'])
|
|
487
|
-
await git.commit('Initial commit')
|
|
488
|
-
|
|
489
|
-
// Create GitManager and ensure author
|
|
490
|
-
const manager = new GitManager({ repoPath: tmpDir })
|
|
491
|
-
await expect(
|
|
492
|
-
manager.ensureAuthor({ name: 'Bot User', email: 'bot@example.com' }),
|
|
493
|
-
).resolves.not.toThrow()
|
|
494
|
-
|
|
495
|
-
// Verify author was set
|
|
496
|
-
const config = await git.listConfig()
|
|
497
|
-
expect(config.all['user.name']).toBe('Bot User')
|
|
498
|
-
expect(config.all['user.email']).toBe('bot@example.com')
|
|
499
|
-
})
|
|
500
|
-
|
|
501
|
-
it('throws error when trying to set author in non-managed repository', async () => {
|
|
502
|
-
// Setup: create repo WITHOUT canopycms.managed marker
|
|
503
|
-
const git = simpleGit({ baseDir: tmpDir })
|
|
504
|
-
await git.init()
|
|
505
|
-
await git.addConfig('user.name', 'Regular User')
|
|
506
|
-
await git.addConfig('user.email', 'user@example.com')
|
|
507
|
-
|
|
508
|
-
// Create GitManager and try to ensure author - should fail
|
|
509
|
-
const manager = new GitManager({ repoPath: tmpDir })
|
|
510
|
-
await expect(
|
|
511
|
-
manager.ensureAuthor({ name: 'Bot User', email: 'bot@example.com' }),
|
|
512
|
-
).rejects.toThrow(/Cannot set git bot author in non-managed repository/)
|
|
513
|
-
|
|
514
|
-
// Verify author was NOT changed
|
|
515
|
-
const config = await git.listConfig()
|
|
516
|
-
expect(config.all['user.name']).toBe('Regular User')
|
|
517
|
-
expect(config.all['user.email']).toBe('user@example.com')
|
|
518
|
-
})
|
|
519
|
-
|
|
520
|
-
it('provides helpful error message for non-managed repos', async () => {
|
|
521
|
-
const git = simpleGit({ baseDir: tmpDir })
|
|
522
|
-
await git.init()
|
|
523
|
-
|
|
524
|
-
const manager = new GitManager({ repoPath: tmpDir })
|
|
525
|
-
await expect(manager.ensureAuthor({ name: 'Bot', email: 'bot@test.com' })).rejects.toThrow(
|
|
526
|
-
/Bot identity should only be set in CanopyCMS branch clones/,
|
|
527
|
-
)
|
|
528
|
-
await expect(manager.ensureAuthor({ name: 'Bot', email: 'bot@test.com' })).rejects.toThrow(
|
|
529
|
-
/If this is a test workspace, add "git config canopycms.managed true"/,
|
|
530
|
-
)
|
|
531
|
-
})
|
|
532
|
-
|
|
533
|
-
it('only updates author if values differ', async () => {
|
|
534
|
-
// Setup: managed repo with existing author
|
|
535
|
-
await initTestRepo(tmpDir)
|
|
536
|
-
|
|
537
|
-
const manager = new GitManager({ repoPath: tmpDir })
|
|
538
|
-
// Spy on the manager's internal git instance
|
|
539
|
-
const addConfigSpy = vi.spyOn(manager['git'], 'addConfig')
|
|
540
|
-
|
|
541
|
-
// First call: should update (values differ from Test Bot / test@canopycms.test)
|
|
542
|
-
await manager.ensureAuthor({ name: 'New Name', email: 'new@example.com' })
|
|
543
|
-
expect(addConfigSpy).toHaveBeenCalledWith('user.name', 'New Name')
|
|
544
|
-
expect(addConfigSpy).toHaveBeenCalledWith('user.email', 'new@example.com')
|
|
545
|
-
|
|
546
|
-
addConfigSpy.mockClear()
|
|
547
|
-
|
|
548
|
-
// Second call with same values: should NOT update
|
|
549
|
-
await manager.ensureAuthor({ name: 'New Name', email: 'new@example.com' })
|
|
550
|
-
expect(addConfigSpy).not.toHaveBeenCalled()
|
|
551
|
-
})
|
|
552
|
-
})
|