@@ -3,17 +3,30 @@ import { flexibleBoolean } from "../utils";
33
44// ============================================================================
55// CONSOLIDATED WRITE SCHEMAS (Issue #16)
6- // Future: Consider Zod discriminated unions for compile-time action validation
6+ // Using Zod discriminated unions for compile-time action validation
77// ============================================================================
88
9- // manage_repository: Consolidates create_repository, fork_repository (2 → 1)
10- export const ManageRepositorySchema = z . object ( {
11- action : z
12- . enum ( [ "create" , "fork" ] )
13- . describe ( "Operation: create=new repository, fork=copy existing repository." ) ,
9+ // Common options shared between create and fork actions
10+ const CommonRepositoryOptions = {
11+ issues_enabled : flexibleBoolean . optional ( ) . describe ( "Enable issue tracking." ) ,
12+ merge_requests_enabled : flexibleBoolean . optional ( ) . describe ( "Enable merge requests." ) ,
13+ jobs_enabled : flexibleBoolean . optional ( ) . describe ( "Enable CI/CD jobs." ) ,
14+ wiki_enabled : flexibleBoolean . optional ( ) . describe ( "Enable project wiki." ) ,
15+ snippets_enabled : flexibleBoolean . optional ( ) . describe ( "Enable code snippets." ) ,
16+ lfs_enabled : flexibleBoolean . optional ( ) . describe ( "Enable Git LFS." ) ,
17+ request_access_enabled : flexibleBoolean . optional ( ) . describe ( "Allow access requests." ) ,
18+ only_allow_merge_if_pipeline_succeeds : flexibleBoolean
19+ . optional ( )
20+ . describe ( "Require passing pipelines for merge." ) ,
21+ only_allow_merge_if_all_discussions_are_resolved : flexibleBoolean
22+ . optional ( )
23+ . describe ( "Require resolved discussions for merge." ) ,
24+ } ;
1425
15- // For "create" action
16- name : z . string ( ) . optional ( ) . describe ( 'Project name (required for "create" action).' ) ,
26+ // manage_repository: Discriminated union for create vs fork
27+ const CreateRepositoryAction = z . object ( {
28+ action : z . literal ( "create" ) . describe ( "Create a new repository." ) ,
29+ name : z . string ( ) . describe ( "Project name (required for create)." ) ,
1730 namespace : z
1831 . string ( )
1932 . optional ( )
@@ -24,34 +37,35 @@ export const ManageRepositorySchema = z.object({
2437 . optional ( )
2538 . describe ( "Project visibility level." ) ,
2639 initialize_with_readme : flexibleBoolean . optional ( ) . describe ( "Create initial README.md file." ) ,
40+ ...CommonRepositoryOptions ,
41+ } ) ;
2742
28- // For "fork" action
29- // Note: fork_name/fork_path are distinct from create's name to avoid schema conflicts.
30- // Handler maps these to GitLab API's 'name'/'path' params for fork endpoint.
43+ // fork_name/fork_path are distinct from create's name to avoid schema conflicts in the
44+ // discriminated union. Handler maps these to GitLab API's name/path parameters.
45+ const ForkRepositoryAction = z . object ( {
46+ action : z . literal ( "fork" ) . describe ( "Fork an existing repository." ) ,
3147 project_id : z . coerce
48+ . string ( )
49+ . describe ( "Source project to fork (required for fork). Numeric ID or URL-encoded path." ) ,
50+ namespace : z . string ( ) . optional ( ) . describe ( "Target namespace ID or path for fork." ) ,
51+ namespace_path : z . string ( ) . optional ( ) . describe ( "Target namespace path for fork." ) ,
52+ fork_name : z
3253 . string ( )
3354 . optional ( )
34- . describe ( 'Source project to fork (required for "fork" action).' ) ,
35- namespace_path : z . string ( ) . optional ( ) . describe ( "Target namespace for fork." ) ,
36- fork_name : z . string ( ) . optional ( ) . describe ( "New name for forked project (maps to API 'name')." ) ,
37- fork_path : z . string ( ) . optional ( ) . describe ( "New path for forked project (maps to API 'path')." ) ,
38-
39- // Common creation options
40- issues_enabled : flexibleBoolean . optional ( ) . describe ( "Enable issue tracking." ) ,
41- merge_requests_enabled : flexibleBoolean . optional ( ) . describe ( "Enable merge requests." ) ,
42- jobs_enabled : flexibleBoolean . optional ( ) . describe ( "Enable CI/CD jobs." ) ,
43- wiki_enabled : flexibleBoolean . optional ( ) . describe ( "Enable project wiki." ) ,
44- snippets_enabled : flexibleBoolean . optional ( ) . describe ( "Enable code snippets." ) ,
45- lfs_enabled : flexibleBoolean . optional ( ) . describe ( "Enable Git LFS." ) ,
46- request_access_enabled : flexibleBoolean . optional ( ) . describe ( "Allow access requests." ) ,
47- only_allow_merge_if_pipeline_succeeds : flexibleBoolean
48- . optional ( )
49- . describe ( "Require passing pipelines for merge." ) ,
50- only_allow_merge_if_all_discussions_are_resolved : flexibleBoolean
55+ . describe ( "New name for forked project (maps to API 'name' parameter)." ) ,
56+ fork_path : z
57+ . string ( )
5158 . optional ( )
52- . describe ( "Require resolved discussions for merge." ) ,
59+ . describe ( "New path for forked project (maps to API 'path' parameter)." ) ,
60+ ...CommonRepositoryOptions ,
5361} ) ;
5462
63+ export const ManageRepositorySchema = z
64+ . discriminatedUnion ( "action" , [ CreateRepositoryAction , ForkRepositoryAction ] )
65+ . describe (
66+ "REPOSITORY MANAGEMENT: Create or fork GitLab projects. Use 'create' with name for new project. Use 'fork' with project_id to copy existing project."
67+ ) ;
68+
5569// ============================================================================
5670// KEPT AS-IS WRITE SCHEMAS
5771// ============================================================================
@@ -81,96 +95,35 @@ export const CreateGroupSchema = z.object({
8195 avatar : z . string ( ) . optional ( ) . describe ( "Group avatar URL." ) ,
8296} ) ;
8397
84- // Todos management (write operations)
85- export const ManageTodosSchema = z . object ( {
86- action : z
87- . enum ( [ "mark_done" , "mark_all_done" , "restore" ] )
88- . describe (
89- "Action: mark_done=complete single todo, mark_all_done=complete all, restore=reopen completed."
90- ) ,
91- id : z
92- . number ( )
93- . int ( )
94- . positive ( )
95- . optional ( )
96- . describe ( "Todo ID (required for mark_done and restore)." ) ,
98+ // manage_todos: Discriminated union for mark_done/mark_all_done/restore
99+ const MarkDoneTodoAction = z . object ( {
100+ action : z . literal ( "mark_done" ) . describe ( "Mark a single todo as done." ) ,
101+ id : z . number ( ) . int ( ) . positive ( ) . describe ( "Todo ID to mark as done (required)." ) ,
97102} ) ;
98103
99- // ============================================================================
100- // DEPRECATED WRITE SCHEMAS (kept for backward compatibility)
101- // ============================================================================
102-
103- // @deprecated Use ManageRepositorySchema with action: "create"
104- export const CreateRepositorySchema = z . object ( {
105- name : z . string ( ) . describe ( "Project display name." ) ,
106- namespace : z . string ( ) . optional ( ) . describe ( "Target namespace path." ) ,
107- description : z . string ( ) . optional ( ) . describe ( "Project description." ) ,
108- issues_enabled : flexibleBoolean . optional ( ) ,
109- merge_requests_enabled : flexibleBoolean . optional ( ) ,
110- jobs_enabled : flexibleBoolean . optional ( ) ,
111- wiki_enabled : flexibleBoolean . optional ( ) ,
112- snippets_enabled : flexibleBoolean . optional ( ) ,
113- resolve_outdated_diff_discussions : flexibleBoolean . optional ( ) ,
114- container_registry_enabled : flexibleBoolean . optional ( ) ,
115- container_registry_access_level : z . enum ( [ "disabled" , "private" , "enabled" ] ) . optional ( ) ,
116- shared_runners_enabled : flexibleBoolean . optional ( ) ,
117- visibility : z . enum ( [ "private" , "internal" , "public" ] ) . optional ( ) ,
118- import_url : z . string ( ) . optional ( ) ,
119- public_jobs : flexibleBoolean . optional ( ) ,
120- only_allow_merge_if_pipeline_succeeds : flexibleBoolean . optional ( ) ,
121- allow_merge_on_skipped_pipeline : flexibleBoolean . optional ( ) ,
122- only_allow_merge_if_all_discussions_are_resolved : flexibleBoolean . optional ( ) ,
123- merge_method : z . enum ( [ "merge" , "rebase_merge" , "ff" ] ) . optional ( ) ,
124- autoclose_referenced_issues : flexibleBoolean . optional ( ) ,
125- suggestion_commit_message : z . string ( ) . optional ( ) ,
126- remove_source_branch_after_merge : flexibleBoolean . optional ( ) ,
127- lfs_enabled : flexibleBoolean . optional ( ) ,
128- request_access_enabled : flexibleBoolean . optional ( ) ,
129- tag_list : z . array ( z . string ( ) ) . optional ( ) ,
130- printing_merge_request_link_enabled : flexibleBoolean . optional ( ) ,
131- build_git_strategy : z . enum ( [ "fetch" , "clone" ] ) . optional ( ) ,
132- build_timeout : z . number ( ) . optional ( ) ,
133- auto_cancel_pending_pipelines : z . enum ( [ "disabled" , "enabled" ] ) . optional ( ) ,
134- build_coverage_regex : z . string ( ) . optional ( ) ,
135- ci_config_path : z . string ( ) . optional ( ) ,
136- auto_devops_enabled : flexibleBoolean . optional ( ) ,
137- auto_devops_deploy_strategy : z . enum ( [ "continuous" , "manual" , "timed_incremental" ] ) . optional ( ) ,
138- repository_storage : z . string ( ) . optional ( ) ,
139- approvals_before_merge : z . number ( ) . optional ( ) ,
140- external_authorization_classification_label : z . string ( ) . optional ( ) ,
141- mirror : flexibleBoolean . optional ( ) ,
142- mirror_trigger_builds : flexibleBoolean . optional ( ) ,
143- initialize_with_readme : flexibleBoolean . optional ( ) ,
144- template_name : z . string ( ) . optional ( ) ,
145- template_project_id : z . number ( ) . optional ( ) ,
146- use_custom_template : flexibleBoolean . optional ( ) ,
147- group_with_project_templates_id : z . number ( ) . optional ( ) ,
148- packages_enabled : flexibleBoolean . optional ( ) ,
149- service_desk_enabled : flexibleBoolean . optional ( ) ,
150- compliance_frameworks : z . array ( z . string ( ) ) . optional ( ) ,
104+ const MarkAllDoneTodoAction = z . object ( {
105+ action : z . literal ( "mark_all_done" ) . describe ( "Mark all todos as done." ) ,
151106} ) ;
152107
153- // @deprecated Use ManageRepositorySchema with action: "fork"
154- export const ForkRepositorySchema = z . object ( {
155- project_id : z . coerce . string ( ) . describe ( "Source project to fork." ) ,
156- namespace : z . string ( ) . optional ( ) . describe ( "Target namespace." ) ,
157- namespace_path : z . string ( ) . optional ( ) . describe ( "Target namespace path." ) ,
158- name : z . string ( ) . optional ( ) . describe ( "Fork name." ) ,
159- path : z . string ( ) . optional ( ) . describe ( "Fork path." ) ,
108+ const RestoreTodoAction = z . object ( {
109+ action : z . literal ( "restore" ) . describe ( "Restore a completed todo to pending." ) ,
110+ id : z . number ( ) . int ( ) . positive ( ) . describe ( "Todo ID to restore (required)." ) ,
160111} ) ;
161112
113+ export const ManageTodosSchema = z
114+ . discriminatedUnion ( "action" , [ MarkDoneTodoAction , MarkAllDoneTodoAction , RestoreTodoAction ] )
115+ . describe (
116+ "TODO ACTIONS: Manage GitLab todo items. mark_done requires id, mark_all_done clears all, restore requires id."
117+ ) ;
118+
162119// ============================================================================
163120// TYPE EXPORTS
164121// ============================================================================
165122
166123// Consolidated types
167124export type ManageRepositoryOptions = z . infer < typeof ManageRepositorySchema > ;
125+ export type ManageTodosOptions = z . infer < typeof ManageTodosSchema > ;
168126
169127// Kept as-is types
170128export type CreateBranchOptions = z . infer < typeof CreateBranchSchema > ;
171129export type CreateGroupOptions = z . infer < typeof CreateGroupSchema > ;
172- export type ManageTodosOptions = z . infer < typeof ManageTodosSchema > ;
173-
174- // Deprecated types
175- export type CreateRepositoryOptions = z . infer < typeof CreateRepositorySchema > ;
176- export type ForkRepositoryOptions = z . infer < typeof ForkRepositorySchema > ;
0 commit comments