Coverage for tools / gitlab_projects.py: 77%
98 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-02 18:55 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-02 18:55 +0000
1"""Perform actions on gitlab projects."""
3import sys
4from argparse import ArgumentDefaultsHelpFormatter, Namespace
5from pathlib import Path
7from sel_tools.code_evaluation.evaluate_code import evaluate_code
8from sel_tools.code_evaluation.jobs.factory import EvaluationJobFactory
9from sel_tools.code_evaluation.report import write_evaluation_report_for_student_comments, write_evaluation_reports
10from sel_tools.diff_creation.create_diff import create_diff
11from sel_tools.diff_creation.report import write_diff_reports, write_report_for_inactive_student_repos
12from sel_tools.file_export.export_item import export_items
13from sel_tools.file_parsing.slide_parser import get_tasks_from_slides
14from sel_tools.gitlab_api.add_user import add_users
15from sel_tools.gitlab_api.comment_issue import comment_issues
16from sel_tools.gitlab_api.create_commit import commit_changes, upload_files
17from sel_tools.gitlab_api.create_issue import create_issues
18from sel_tools.gitlab_api.fetch_repo import fetch_repos
19from sel_tools.gitlab_api.instance import create_gitlab_instance
20from sel_tools.utils.args import ArgumentParserFactory
21from sel_tools.utils.comment import Comment
22from sel_tools.utils.student_config import read_student_repo_info_from_config_file
23from sel_tools.utils.task import configure_tasks
26def edit_create_issues(args: Namespace) -> None:
27 """Default action for create_issues subcommand."""
28 tasks = get_tasks_from_slides(Path(args.issue_md_slides.name))
29 tasks = configure_tasks(tasks, args.due_date, args.homework_number)
30 create_issues(
31 tasks,
32 read_student_repo_info_from_config_file(args.student_repo_info_file.name),
33 create_gitlab_instance(args.gitlab_token),
34 )
37def edit_comment_issue(args: Namespace) -> None:
38 """Default action for comment_issue subcommand."""
39 comment = Comment.create(args.issue_number, args.message, args.state_event)
40 comment_issues(
41 comment,
42 read_student_repo_info_from_config_file(args.student_repo_info_file.name),
43 create_gitlab_instance(args.gitlab_token),
44 )
47def edit_fetch_code(args: Namespace) -> None:
48 """Default action for fetch_code subcommand."""
49 fetch_repos(
50 args.workspace,
51 read_student_repo_info_from_config_file(args.student_repo_info_file.name),
52 create_gitlab_instance(args.gitlab_token),
53 )
56def edit_evaluate_code(args: Namespace) -> None:
57 """Default action for evaluate_code subcommand."""
58 gitlab_projects = fetch_repos(
59 args.workspace,
60 read_student_repo_info_from_config_file(args.student_repo_info_file.name),
61 create_gitlab_instance(args.gitlab_token),
62 )
63 factory = EvaluationJobFactory.load_factory_from_file(args.job_factory)
64 evaluation_reports = evaluate_code(factory, gitlab_projects, args.homework_number, args.evaluation_date)
65 write_evaluation_reports(evaluation_reports, f"homework-{args.homework_number}-report")
66 write_evaluation_report_for_student_comments(evaluation_reports, args.workspace)
67 diff_reports = create_diff(
68 [project.local_path for project in gitlab_projects],
69 args.date_last_homework,
70 args.evaluation_date,
71 )
72 write_diff_reports(diff_reports, f"homework-{args.homework_number}-diff")
73 write_report_for_inactive_student_repos(diff_reports, args.workspace)
76def edit_upload_files(args: Namespace) -> None:
77 """Default action for upload_files subcommand."""
78 upload_files(
79 args.source_path,
80 read_student_repo_info_from_config_file(args.student_repo_info_file.name),
81 create_gitlab_instance(args.gitlab_token),
82 )
85def edit_commit_changes(args: Namespace) -> None:
86 """Default action for commit_changes subcommand."""
87 gitlab_projects = fetch_repos(
88 args.workspace,
89 read_student_repo_info_from_config_file(args.student_repo_info_file.name),
90 create_gitlab_instance(args.gitlab_token),
91 )
92 student_repos = [project.local_path for project in gitlab_projects]
93 export_items(args.source_path, student_repos, args.keep_solutions)
94 commit_changes(student_repos, args.message)
97def edit_add_users(args: Namespace) -> None:
98 """Default action for add_users subcommand."""
99 add_users(
100 read_student_repo_info_from_config_file(args.student_repo_info_file.name),
101 Path(args.student_group_info_file.name),
102 create_gitlab_instance(args.gitlab_token),
103 )
106def parse_arguments(arguments: list[str]) -> Namespace:
107 """Parse CLI arguments."""
108 # pylint: disable=too-many-locals
110 parser = ArgumentParserFactory.default_parser(__doc__).parser
111 subparsers = parser.add_subparsers(title="actions", dest="actions", help="sub-command help", required=True)
113 # Common arguments
114 factory = ArgumentParserFactory.parent_parser()
115 factory.add_student_repo_info_file()
116 factory.add_gitlab_token()
118 # Create issues parser
119 create_issue_factory = factory.copy()
120 create_issue_factory.add_issue_md_slide()
121 create_issue_factory.add_homework_number()
122 create_issue_factory.add_due_date()
123 parser_issues = subparsers.add_parser(
124 "create_issues",
125 parents=[create_issue_factory.parser],
126 formatter_class=ArgumentDefaultsHelpFormatter,
127 description="Create Gitlab issues from homework slides",
128 help="Create Gitlab issues from homework slides",
129 )
130 parser_issues.set_defaults(func=edit_create_issues)
132 # Comment issues parser
133 comment_issue_factory = factory.copy()
134 comment_issue_factory.add_issue_number()
135 comment_issue_factory.add_message("Message or path to a .md file")
136 comment_issue_factory.add_state_event()
137 parser_comment = subparsers.add_parser(
138 "comment_issue",
139 parents=[comment_issue_factory.parser],
140 formatter_class=ArgumentDefaultsHelpFormatter,
141 description="Comment to Gitlab issues via message or markdown slides",
142 help="Comment to Gitlab issues via message or markdown slides",
143 )
144 parser_comment.set_defaults(func=edit_comment_issue)
146 # Fetch code parser
147 fetch_code_factory = factory.copy()
148 fetch_code_factory.add_workspace()
149 parser_fetch = subparsers.add_parser(
150 "fetch_code",
151 parents=[fetch_code_factory.parser],
152 formatter_class=ArgumentDefaultsHelpFormatter,
153 description="Fetch (clone or pull) Gitlab repositories",
154 help="Fetch (clone or pull) Gitlab repositories",
155 )
156 parser_fetch.set_defaults(func=edit_fetch_code)
158 # Evaluate code parser
159 evaluate_code_factory = factory.copy()
160 evaluate_code_factory.add_homework_number()
161 evaluate_code_factory.add_job_factory_path()
162 evaluate_code_factory.add_workspace()
163 evaluate_code_factory.add_date_sine_last_homework()
164 evaluate_code_factory.add_evaluation_date()
165 parser_evaluate = subparsers.add_parser(
166 "evaluate_code",
167 parents=[evaluate_code_factory.parser],
168 formatter_class=ArgumentDefaultsHelpFormatter,
169 description="Fetch (clone or pull) Gitlab repositories and evaluate code",
170 help="Fetch (clone or pull) Gitlab repositories and evaluate code",
171 )
172 parser_evaluate.set_defaults(func=edit_evaluate_code)
174 # Upload files parser
175 upload_files_factory = factory.copy()
176 upload_files_factory.add_source_folder(None)
177 parser_upload_files = subparsers.add_parser(
178 "upload_files",
179 parents=[upload_files_factory.parser],
180 formatter_class=ArgumentDefaultsHelpFormatter,
181 description="Upload files via commit to Gitlab from source folder",
182 help="Upload files via commit to Gitlab from source folder",
183 )
184 parser_upload_files.set_defaults(func=edit_upload_files)
186 # Commit changes parser
187 commit_changes_factory = factory.copy()
188 commit_changes_factory.add_source_folder(None)
189 commit_changes_factory.add_message("Commit message used for all repos")
190 commit_changes_factory.add_workspace()
191 commit_changes_factory.add_keep_solutions()
192 parser_commit_changes = subparsers.add_parser(
193 "commit_changes",
194 parents=[commit_changes_factory.parser],
195 formatter_class=ArgumentDefaultsHelpFormatter,
196 description="Copy source folder to workspace and commit the changes",
197 help="Copy source folder to workspace and commit the changes",
198 )
199 parser_commit_changes.set_defaults(func=edit_commit_changes)
201 # Add users parser
202 add_users_factory = factory.copy()
203 add_users_factory.add_student_group_info_file()
204 parser_add_users = subparsers.add_parser(
205 "add_users",
206 parents=[add_users_factory.parser],
207 formatter_class=ArgumentDefaultsHelpFormatter,
208 description="Add all users to their respective repositories",
209 help="Add all users to their respective repositories",
210 )
211 parser_add_users.set_defaults(func=edit_add_users)
213 return parser.parse_args(arguments[1:])
216def main() -> None:
217 """Main."""
218 args = parse_arguments(sys.argv)
219 args.func(args)
222if __name__ == "__main__":
223 main()