diff --git a/joint_teapot/app.py b/joint_teapot/app.py index c3d8126..c7086c9 100644 --- a/joint_teapot/app.py +++ b/joint_teapot/app.py @@ -287,9 +287,8 @@ def joj3_scoreboard( + f"{settings.gitea_org_name}/{submitter_repo_name}@{commit_hash}\n\n" + f"gitea actions link: {actions_link}" ) - tea.pot.git.add_commit_and_push( - repo_name, [scoreboard_file_name], commit_message - ) + tea.pot.git.add_commit(repo_name, [scoreboard_file_name], commit_message) + tea.pot.git.push(repo_name) @app.command( @@ -373,11 +372,8 @@ def joj3_failed_table( + f"{settings.gitea_org_name}/{submitter_repo_name}@{commit_hash}\n\n" + f"gitea actions link: {actions_link}" ) - tea.pot.git.add_commit_and_push( - repo_name, - [failed_table_file_name], - commit_message, - ) + tea.pot.git.add_commit(repo_name, [failed_table_file_name], commit_message) + tea.pot.git.push(repo_name) @app.command( @@ -428,6 +424,136 @@ def joj3_create_result_issue( tea.pot.gitea.create_issue(submitter_repo_name, title, comment, False) +@app.command( + "joj3-all", + help="run all joj3 tasks", +) +def joj3_all( + env_path: str = Argument("", help="path to .env file"), + score_file_path: str = Argument( + "", help="path to score json file generated by JOJ3" + ), + submitter: str = Argument("", help="submitter ID"), + repo_name: str = Argument( + "", + help="name of grading repo to push failed table file", + ), + submitter_repo_name: str = Argument( + "", + help="repository's name of the submitter", + ), + run_number: str = Argument( + "", + help="gitea actions run number", + ), + scoreboard_file_name: str = Argument( + "scoreboard.csv", help="name of scoreboard file in the gitea repo" + ), + failed_table_file_name: str = Argument( + "failed-table.md", help="name of failed table file in the gitea repo" + ), + exercise_name: str = Argument( + "unknown", + help="name of the exercise that appears on the issue title", + ), + commit_hash: str = Argument( + "", + help="commit hash that triggers gitea actions", + ), + skip_result_issue: bool = Option( + False, + help="skip creating result issue on gitea", + ), + skip_scoreboard: bool = Option( + False, + help="skip creating scoreboard on gitea", + ), + skip_failed_table: bool = Option( + False, + help="skip creating failed table on gitea", + ), +) -> None: + set_settings(Settings(_env_file=env_path)) + set_logger(settings.stderr_log_level, diagnose=False, backtrace=False) + logger.info(f"debug log to file: {settings.log_file_path}") + actions_link = ( + f"https://{settings.gitea_domain_name}{settings.gitea_suffix}/" + + f"{settings.gitea_org_name}/{submitter_repo_name}/" + + f"actions/runs/{run_number}" + ) + submitter_repo_link = ( + f"https://{settings.gitea_domain_name}{settings.gitea_suffix}/" + + f"{settings.gitea_org_name}/{submitter_repo_name}" + ) + if not skip_result_issue: + title, comment = joj3.generate_title_and_comment( + score_file_path, + actions_link, + run_number, + exercise_name, + submitter, + commit_hash, + ) + tea.pot.gitea.create_issue(submitter_repo_name, title, comment, False) + if skip_scoreboard and skip_failed_table: + return + tea.pot.git # trigger lazy load + lock_file_path = os.path.join( + settings.repos_dir, repo_name, settings.joj3_lock_file_path + ) + logger.info( + f"try to acquire lock, file path: {lock_file_path}, " + + f"timeout: {settings.joj3_lock_file_timeout}" + ) + with FileLock(lock_file_path, timeout=settings.joj3_lock_file_timeout).acquire(): + logger.info("file lock acquired") + repo_path = tea.pot.git.repo_clean_and_checkout(repo_name, "grading") + repo: Repo = tea.pot.git.get_repo(repo_name) + if "grading" not in repo.remote().refs: + logger.error( + '"grading" branch not found in remote, create and push it to origin first.' + ) + return + if "grading" not in repo.branches: + logger.error('"grading" branch not found in local, create it first.') + return + repo.git.reset("--hard", "origin/grading") + if not skip_scoreboard: + joj3.generate_scoreboard( + score_file_path, + submitter, + os.path.join(repo_path, scoreboard_file_name), + exercise_name, + ) + tea.pot.git.add_commit( + repo_name, + [scoreboard_file_name], + ( + f"joj3: update scoreboard by @{submitter} in " + + f"{settings.gitea_org_name}/{submitter_repo_name}@{commit_hash}\n\n" + + f"gitea actions link: {actions_link}" + ), + ) + if not skip_failed_table: + joj3.generate_failed_table( + score_file_path, + submitter_repo_name, + submitter_repo_link, + os.path.join(repo_path, failed_table_file_name), + actions_link, + ) + tea.pot.git.add_commit( + repo_name, + [failed_table_file_name], + ( + f"joj3: update failed table by @{submitter} in " + + f"{settings.gitea_org_name}/{submitter_repo_name}@{commit_hash}\n\n" + + f"gitea actions link: {actions_link}" + ), + ) + tea.pot.git.push(repo_name) + + if __name__ == "__main__": try: app() diff --git a/joint_teapot/workers/git.py b/joint_teapot/workers/git.py index 4bf2c1f..321effe 100644 --- a/joint_teapot/workers/git.py +++ b/joint_teapot/workers/git.py @@ -102,7 +102,7 @@ class Git: raise return repo_dir - def add_commit_and_push( + def add_commit( self, repo_name: str, files_to_add: List[str], commit_message: str ) -> None: repo: Repo = self.get_repo(repo_name) @@ -116,4 +116,7 @@ class Git: continue if repo.is_dirty(untracked_files=True) or repo.index.diff(None): repo.index.commit(commit_message) - repo.remote(name="origin").push() + + def push(self, repo_name: str) -> None: + repo: Repo = self.get_repo(repo_name) + repo.remote(name="origin").push()