Coverage for tools/gitlab_projects.py: 76%

97 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-10-06 08:15 +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 parser = ArgumentParserFactory.default_parser(__doc__).parser 

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

109 

110 # Common arguments 

111 factory = ArgumentParserFactory.parent_parser() 

112 factory.add_student_repo_info_file() 

113 factory.add_gitlab_token() 

114 

115 # Create issues parser 

116 create_issue_factory = factory.copy() 

117 create_issue_factory.add_issue_md_slide() 

118 create_issue_factory.add_homework_number() 

119 create_issue_factory.add_due_date() 

120 parser_issues = subparsers.add_parser( 

121 "create_issues", 

122 parents=[create_issue_factory.parser], 

123 formatter_class=ArgumentDefaultsHelpFormatter, 

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

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

126 ) 

127 parser_issues.set_defaults(func=edit_create_issues) 

128 

129 # Comment issues parser 

130 comment_issue_factory = factory.copy() 

131 comment_issue_factory.add_issue_number() 

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

133 comment_issue_factory.add_state_event() 

134 parser_comment = subparsers.add_parser( 

135 "comment_issue", 

136 parents=[comment_issue_factory.parser], 

137 formatter_class=ArgumentDefaultsHelpFormatter, 

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

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

140 ) 

141 parser_comment.set_defaults(func=edit_comment_issue) 

142 

143 # Fetch code parser 

144 fetch_code_factory = factory.copy() 

145 fetch_code_factory.add_workspace() 

146 parser_fetch = subparsers.add_parser( 

147 "fetch_code", 

148 parents=[fetch_code_factory.parser], 

149 formatter_class=ArgumentDefaultsHelpFormatter, 

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

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

152 ) 

153 parser_fetch.set_defaults(func=edit_fetch_code) 

154 

155 # Evaluate code parser 

156 evaluate_code_factory = factory.copy() 

157 evaluate_code_factory.add_homework_number() 

158 evaluate_code_factory.add_job_factory_path() 

159 evaluate_code_factory.add_workspace() 

160 evaluate_code_factory.add_date_sine_last_homework() 

161 evaluate_code_factory.add_evaluation_date() 

162 parser_evaluate = subparsers.add_parser( 

163 "evaluate_code", 

164 parents=[evaluate_code_factory.parser], 

165 formatter_class=ArgumentDefaultsHelpFormatter, 

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

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

168 ) 

169 parser_evaluate.set_defaults(func=edit_evaluate_code) 

170 

171 # Upload files parser 

172 upload_files_factory = factory.copy() 

173 upload_files_factory.add_source_folder(None) 

174 parser_upload_files = subparsers.add_parser( 

175 "upload_files", 

176 parents=[upload_files_factory.parser], 

177 formatter_class=ArgumentDefaultsHelpFormatter, 

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

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

180 ) 

181 parser_upload_files.set_defaults(func=edit_upload_files) 

182 

183 # Commit changes parser 

184 commit_changes_factory = factory.copy() 

185 commit_changes_factory.add_source_folder(None) 

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

187 commit_changes_factory.add_workspace() 

188 commit_changes_factory.add_keep_solutions() 

189 parser_commit_changes = subparsers.add_parser( 

190 "commit_changes", 

191 parents=[commit_changes_factory.parser], 

192 formatter_class=ArgumentDefaultsHelpFormatter, 

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

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

195 ) 

196 parser_commit_changes.set_defaults(func=edit_commit_changes) 

197 

198 # Add users parser 

199 add_users_factory = factory.copy() 

200 add_users_factory.add_student_group_info_file() 

201 parser_add_users = subparsers.add_parser( 

202 "add_users", 

203 parents=[add_users_factory.parser], 

204 formatter_class=ArgumentDefaultsHelpFormatter, 

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

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

207 ) 

208 parser_add_users.set_defaults(func=edit_add_users) 

209 

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

211 

212 

213def main() -> None: 

214 """Main.""" 

215 args = parse_arguments(sys.argv) 

216 args.func(args) 

217 

218 

219if __name__ == "__main__": 

220 main()