Coverage for tools / gitlab_projects.py: 76%

97 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-05-21 08:53 +0000

1"""Perform actions on gitlab projects.""" 

2 

3import sys 

4from argparse import ArgumentDefaultsHelpFormatter, Namespace 

5 

6from sel_tools.code_evaluation.evaluate_code import evaluate_code 

7from sel_tools.code_evaluation.jobs.factory import EvaluationJobFactory 

8from sel_tools.code_evaluation.report import write_evaluation_report_for_student_comments, write_evaluation_reports 

9from sel_tools.diff_creation.create_diff import create_diff 

10from sel_tools.diff_creation.report import write_diff_reports, write_report_for_inactive_student_repos 

11from sel_tools.file_export.export_item import export_items 

12from sel_tools.file_parsing.slide_parser import get_tasks_from_slides 

13from sel_tools.gitlab_api.add_user import add_users 

14from sel_tools.gitlab_api.comment_issue import comment_issues 

15from sel_tools.gitlab_api.create_commit import commit_changes, upload_files 

16from sel_tools.gitlab_api.create_issue import create_issues 

17from sel_tools.gitlab_api.fetch_repo import fetch_repos 

18from sel_tools.gitlab_api.instance import create_gitlab_instance 

19from sel_tools.utils.args import ArgumentParserFactory 

20from sel_tools.utils.comment import Comment 

21from sel_tools.utils.student_config import read_student_repo_info_from_config_file 

22from sel_tools.utils.task import configure_tasks 

23 

24 

25def edit_create_issues(args: Namespace) -> None: 

26 """Default action for create_issues subcommand.""" 

27 tasks = get_tasks_from_slides(args.issue_md_slides) 

28 tasks = configure_tasks(tasks, args.due_date, args.homework_number) 

29 create_issues( 

30 tasks, 

31 read_student_repo_info_from_config_file(args.student_repo_info_file), 

32 create_gitlab_instance(args.gitlab_token), 

33 ) 

34 

35 

36def edit_comment_issue(args: Namespace) -> None: 

37 """Default action for comment_issue subcommand.""" 

38 comment = Comment.create(args.issue_number, args.message, args.state_event) 

39 comment_issues( 

40 comment, 

41 read_student_repo_info_from_config_file(args.student_repo_info_file), 

42 create_gitlab_instance(args.gitlab_token), 

43 ) 

44 

45 

46def edit_fetch_code(args: Namespace) -> None: 

47 """Default action for fetch_code subcommand.""" 

48 fetch_repos( 

49 args.workspace, 

50 read_student_repo_info_from_config_file(args.student_repo_info_file), 

51 create_gitlab_instance(args.gitlab_token), 

52 ) 

53 

54 

55def edit_evaluate_code(args: Namespace) -> None: 

56 """Default action for evaluate_code subcommand.""" 

57 gitlab_projects = fetch_repos( 

58 args.workspace, 

59 read_student_repo_info_from_config_file(args.student_repo_info_file), 

60 create_gitlab_instance(args.gitlab_token), 

61 ) 

62 factory = EvaluationJobFactory.load_factory_from_file(args.job_factory) 

63 evaluation_reports = evaluate_code(factory, gitlab_projects, args.homework_number, args.evaluation_date) 

64 write_evaluation_reports(evaluation_reports, f"homework-{args.homework_number}-report") 

65 write_evaluation_report_for_student_comments(evaluation_reports, args.workspace) 

66 diff_reports = create_diff( 

67 [project.local_path for project in gitlab_projects], 

68 args.date_last_homework, 

69 args.evaluation_date, 

70 ) 

71 write_diff_reports(diff_reports, f"homework-{args.homework_number}-diff") 

72 write_report_for_inactive_student_repos(diff_reports, args.workspace) 

73 

74 

75def edit_upload_files(args: Namespace) -> None: 

76 """Default action for upload_files subcommand.""" 

77 upload_files( 

78 args.source_path, 

79 read_student_repo_info_from_config_file(args.student_repo_info_file), 

80 create_gitlab_instance(args.gitlab_token), 

81 ) 

82 

83 

84def edit_commit_changes(args: Namespace) -> None: 

85 """Default action for commit_changes subcommand.""" 

86 gitlab_projects = fetch_repos( 

87 args.workspace, 

88 read_student_repo_info_from_config_file(args.student_repo_info_file), 

89 create_gitlab_instance(args.gitlab_token), 

90 ) 

91 student_repos = [project.local_path for project in gitlab_projects] 

92 export_items(args.source_path, student_repos, args.keep_solutions) 

93 commit_changes(student_repos, args.message) 

94 

95 

96def edit_add_users(args: Namespace) -> None: 

97 """Default action for add_users subcommand.""" 

98 add_users( 

99 read_student_repo_info_from_config_file(args.student_repo_info_file), 

100 args.student_group_info_file, 

101 create_gitlab_instance(args.gitlab_token), 

102 ) 

103 

104 

105def parse_arguments(arguments: list[str]) -> Namespace: 

106 """Parse CLI arguments.""" 

107 # pylint: disable=too-many-locals 

108 

109 parser = ArgumentParserFactory.default_parser(__doc__).parser 

110 subparsers = parser.add_subparsers(title="actions", dest="actions", help="sub-command help", required=True) 

111 

112 # Common arguments 

113 factory = ArgumentParserFactory.parent_parser() 

114 factory.add_student_repo_info_file() 

115 factory.add_gitlab_token() 

116 

117 # Create issues parser 

118 create_issue_factory = factory.copy() 

119 create_issue_factory.add_issue_md_slide() 

120 create_issue_factory.add_homework_number() 

121 create_issue_factory.add_due_date() 

122 parser_issues = subparsers.add_parser( 

123 "create_issues", 

124 parents=[create_issue_factory.parser], 

125 formatter_class=ArgumentDefaultsHelpFormatter, 

126 description="Create Gitlab issues from homework slides", 

127 help="Create Gitlab issues from homework slides", 

128 ) 

129 parser_issues.set_defaults(func=edit_create_issues) 

130 

131 # Comment issues parser 

132 comment_issue_factory = factory.copy() 

133 comment_issue_factory.add_issue_number() 

134 comment_issue_factory.add_message("Message as string or path to an `.md` file with the message") 

135 comment_issue_factory.add_state_event() 

136 parser_comment = subparsers.add_parser( 

137 "comment_issue", 

138 parents=[comment_issue_factory.parser], 

139 formatter_class=ArgumentDefaultsHelpFormatter, 

140 description="Comment to Gitlab issues via message or markdown slides", 

141 help="Comment to Gitlab issues via message or markdown slides", 

142 ) 

143 parser_comment.set_defaults(func=edit_comment_issue) 

144 

145 # Fetch code parser 

146 fetch_code_factory = factory.copy() 

147 fetch_code_factory.add_workspace() 

148 parser_fetch = subparsers.add_parser( 

149 "fetch_code", 

150 parents=[fetch_code_factory.parser], 

151 formatter_class=ArgumentDefaultsHelpFormatter, 

152 description="Fetch (clone or pull) Gitlab repositories", 

153 help="Fetch (clone or pull) Gitlab repositories", 

154 ) 

155 parser_fetch.set_defaults(func=edit_fetch_code) 

156 

157 # Evaluate code parser 

158 evaluate_code_factory = factory.copy() 

159 evaluate_code_factory.add_homework_number() 

160 evaluate_code_factory.add_job_factory_path() 

161 evaluate_code_factory.add_workspace() 

162 evaluate_code_factory.add_date_sine_last_homework() 

163 evaluate_code_factory.add_evaluation_date() 

164 parser_evaluate = subparsers.add_parser( 

165 "evaluate_code", 

166 parents=[evaluate_code_factory.parser], 

167 formatter_class=ArgumentDefaultsHelpFormatter, 

168 description="Fetch (clone or pull) Gitlab repositories and evaluate code", 

169 help="Fetch (clone or pull) Gitlab repositories and evaluate code", 

170 ) 

171 parser_evaluate.set_defaults(func=edit_evaluate_code) 

172 

173 # Upload files parser 

174 upload_files_factory = factory.copy() 

175 upload_files_factory.add_source_folder(None) 

176 parser_upload_files = subparsers.add_parser( 

177 "upload_files", 

178 parents=[upload_files_factory.parser], 

179 formatter_class=ArgumentDefaultsHelpFormatter, 

180 description="Upload files via commit to Gitlab from source folder", 

181 help="Upload files via commit to Gitlab from source folder", 

182 ) 

183 parser_upload_files.set_defaults(func=edit_upload_files) 

184 

185 # Commit changes parser 

186 commit_changes_factory = factory.copy() 

187 commit_changes_factory.add_source_folder(None) 

188 commit_changes_factory.add_message("Commit message used for all repos") 

189 commit_changes_factory.add_workspace() 

190 commit_changes_factory.add_keep_solutions() 

191 parser_commit_changes = subparsers.add_parser( 

192 "commit_changes", 

193 parents=[commit_changes_factory.parser], 

194 formatter_class=ArgumentDefaultsHelpFormatter, 

195 description="Copy source folder to workspace and commit the changes", 

196 help="Copy source folder to workspace and commit the changes", 

197 ) 

198 parser_commit_changes.set_defaults(func=edit_commit_changes) 

199 

200 # Add users parser 

201 add_users_factory = factory.copy() 

202 add_users_factory.add_student_group_info_file() 

203 parser_add_users = subparsers.add_parser( 

204 "add_users", 

205 parents=[add_users_factory.parser], 

206 formatter_class=ArgumentDefaultsHelpFormatter, 

207 description="Add all users to their respective repositories", 

208 help="Add all users to their respective repositories", 

209 ) 

210 parser_add_users.set_defaults(func=edit_add_users) 

211 

212 return parser.parse_args(arguments[1:]) 

213 

214 

215def main() -> None: 

216 """Main.""" 

217 args = parse_arguments(sys.argv) 

218 args.func(args) 

219 

220 

221if __name__ == "__main__": 

222 main()