diff options
Diffstat (limited to 'import_issues.py')
-rwxr-xr-x | import_issues.py | 125 |
1 files changed, 107 insertions, 18 deletions
diff --git a/import_issues.py b/import_issues.py index 245cb55..1c27f80 100755 --- a/import_issues.py +++ b/import_issues.py @@ -27,16 +27,17 @@ # Tickets are created in sr.ht via SMTP, so a working mail setup is required. # Surely using Sourcehut's API would be better. # -# There are a few of big caveats: +# There are a few caveats: # # 1. If all issue IDs from 1 to the max ID are available in your export, and the # tracker you import into is a new tracker, then your Gitlab and Sourcehut issue -# IDs will match up one-to-one. If not, then all bets are off. The ticket -# descriptions in Sourcehut will indicate the original Gitlab ID, but no -# rewriting of text is done, so issue references will be incorrect. By default, -# the script tries to avoid this by checking that all IDs from 1 to the number -# of issues are in the export, and aborting if not. To override this, pass -# --allow-missing-issues. +# IDs will match up one-to-one, and mentions of one ticket from another will +# work. If not, you need to decide how you want to handle this. You can choose +# to create empty Sourcehut tickets for the missing Gitlab issues so that IDs +# still match, by passing --create-missing-issues. Blank issues will be created +# then closed. Alternatively, you can pass --skip-missing-issues to not create +# any extra Sourcehut tickets, but IDs will not line up. If one of these issues +# is needed, this program will tell you. # # 2. Because emails are used to create tickets, we also assume that emails are # processed in the order that they are sent, so that tickets don't get created @@ -253,6 +254,45 @@ def open_ticket( return issue_count +def file_missing_ticket( + *, + smtp, + smtp_delay: float, + mode: str, + srht_owner: str, + srht_tracker: str, + frm: str, + issue_id: int, +) -> int: + global issue_count + + do_mail( + smtp=smtp, + smtp_delay=smtp_delay, + mode=mode, + frm=frm, + to=f"~{srht_owner}/{srht_tracker}@todo.sr.ht", + subject="Missing issue", + body=f"Issue {issue_id} is not known.", + ) + + issue_count += 1 + + # TODO Send these emails at the end, so that there isn't such a need for the + # previous issue to be processed promptly. + close_ticket( + smtp=smtp, + smtp_delay=smtp_delay, + mode=mode, + srht_owner=srht_owner, + srht_tracker=srht_tracker, + frm=frm, + issue_id=issue_count, + closed_at=None, + is_closed=False, # Save one line of text. + ) + + def send_comment( *, smtp, @@ -336,7 +376,8 @@ def run( frm: str, export_dir_path: Path, gitlab_project_url: str, - allow_missing_issues: bool, + skip_missing_issues: bool, + create_missing_issues: bool, ): milestone_jsons = [] with open(export_dir_path / 'milestones.ndjson') as milestones_file: @@ -353,10 +394,21 @@ def run( issue_jsons.append(json.loads(line)) issue_jsons.sort(key=lambda x: x['iid']) - if not allow_missing_issues: - assert [x['iid'] for x in issue_jsons] == list(range(1, len(issue_jsons) + 1)), \ - f"Don't have all issues from 1 to {len(issue_jsons)}, cannot proceed." + max_issue_id = max(x['iid'] for x in issue_jsons) + present_issue_id_set = {x['iid'] for x in issue_jsons} + missing_issue_ids = set(range(1, max_issue_id + 1)) - present_issue_id_set + if missing_issue_ids and not (skip_missing_issues or create_missing_issues): + raise RuntimeError( + f"Don't have all issues from 1 to {max_issue_id}, please pass " + f"--create-missing-issues or --skip-missing-issues to proceed." + ) + + issues_by_id = {} + for issue_json in issue_jsons: + issues_by_id[issue_json['iid']] = issue_json + + # Need to sort notes by date, they seem to come unsorted. for issue_json in issue_jsons: issue_json['notes'].sort(key=lambda x: x['created_at']) @@ -364,8 +416,31 @@ def run( issue_id_map: Dict[int, int] = {} - for issue_json in issue_jsons: - gitlab_issue_id = issue_json['iid'] + # While we're creating tickets, we can't just loop over the sorted + # issue_jsons. We have to loop over potential issue IDs and handle any that + # are missing as well. + for gitlab_issue_id in range(1, max_issue_id + 1): + if gitlab_issue_id not in issues_by_id: + if create_missing_issues: + file_missing_ticket( + smtp=smtp, + smtp_delay=smtp_delay, + mode=mode, + srht_owner=srht_owner, + srht_tracker=srht_tracker, + frm=frm, + issue_id=gitlab_issue_id, + ) + elif not skip_missing_issues: + raise RuntimeError( + f"Internal error, don't know what to do with missing " + f"issue ID {gitlab_issue_id}." + ) + + continue + + issue_json = issues_by_id[gitlab_issue_id] + author_id = issue_json['author_id'] created_by: Optional[str] if USERS is None: @@ -393,10 +468,12 @@ def run( gitlab_ticket_url=f"{gitlab_project_url}/-/issues/{gitlab_issue_id}", ) - if not allow_missing_issues: + if not skip_missing_issues: assert srht_issue_id == gitlab_issue_id, \ f"Internal error, srht_issue_id {srht_issue_id} != " \ - f"gitlab_issue_id {gitlab_issue_id}." + f"gitlab_issue_id {gitlab_issue_id} " \ + f"(skip_missing_issues={skip_missing_issues}, " \ + f"create_missing_issues={create_missing_issues})." issue_id_map[gitlab_issue_id] = srht_issue_id @@ -530,9 +607,15 @@ def main(): ) parser.add_argument( - '--allow-missing-issues', + '--skip-missing-issues', action='store_true', - help="Don't abort if there are missing issue IDs in the export.", + help="Skip missing Gitlab issue IDs; GL and sr.ht IDs will not match.", + ) + + parser.add_argument( + '--create-missing-issues', + action='store_true', + help="Create missing GL issues in sr.ht to make issue IDs match.", ) parser.add_argument( @@ -551,6 +634,11 @@ def main(): mode = args['mode'] frm = args['from'] + skip_missing_issues = args['skip_missing_issues'] + create_missing_issues = args['create_missing_issues'] + assert not (skip_missing_issues and create_missing_issues), \ + f"Can accept at most one of --skip-missing-issues and --create-missing-issues." + if mode == 'print': smtp = None elif mode == 'send': @@ -584,7 +672,8 @@ def main(): frm=frm, export_dir_path=export_dir_path, gitlab_project_url=args['gitlab_project_url'].rstrip('/'), - allow_missing_issues=args['allow_missing_issues'], + skip_missing_issues=args['skip_missing_issues'], + create_missing_issues=args['create_missing_issues'], ) if mode == 'send': |