2023-10-04 17:49:23 +00:00
import os
import sys
from dotenv import load_dotenv
import requests
load_dotenv ( )
FORGEJO_INSTANCE = os . getenv ( " FORGEJO_INSTANCE " , " https://codeberg.org " )
FORGEJO_API_TOKEN = os . getenv ( " FORGEJO_API_TOKEN " )
API_GET_ISSUE = " {instance} /api/v1/repos/ {owner} / {repo} /issues/ {index} "
2023-10-04 20:19:03 +00:00
API_GET_ISSUE = " {instance} /api/v1/repos/ {owner} / {repo} /issues/ {index} "
API_PATCH_ISSUE = " {instance} /api/v1/repos/ {owner} / {repo} /issues/ {index} "
2023-10-04 17:49:23 +00:00
API_CREATE_ISSUE = " {instance} /api/v1/repos/ {owner} / {repo} /issues "
2023-10-04 19:46:42 +00:00
API_GET_COMMENTS = " {instance} /api/v1/repos/ {owner} / {repo} /issues/ {index} /comments "
API_CREATE_COMMENT = " {instance} /api/v1/repos/ {owner} / {repo} /issues/ {index} /comments "
2023-10-04 17:49:23 +00:00
def move_issue ( source_owner , source_repo , issue_number , destination_owner , destination_repo ) :
get_issue_url = API_GET_ISSUE . format ( instance = FORGEJO_INSTANCE , owner = source_owner , repo = source_repo , index = issue_number )
# print(get_issue_url)
response = requests . get ( get_issue_url , params = { " access_token " : FORGEJO_API_TOKEN } )
json_response = response . json ( )
# Not 100% certain this can ever give a message, but create below does on error
message = json_response . pop ( ' message ' , False )
if message :
print ( message )
2023-10-04 20:19:03 +00:00
sys . exit ( " Error getting issue. " )
else :
old_issue_url = json_response [ ' html_url ' ]
2023-10-04 17:49:23 +00:00
2023-10-04 18:29:19 +00:00
milestone = json_response . pop ( ' milestone ' , { } )
if milestone :
print ( f " We have removed the milestone { milestone [ ' title ' ] } from this issue (milestones are specific to repositories). " )
# Note that pop has already thrown out the milestone from json_response
2023-10-04 17:49:23 +00:00
2023-10-05 02:29:16 +00:00
labels = json_response . pop ( ' labels ' , { } )
if labels :
print ( " Labels are unique per project and rather than messing with creating ones with the same name we have removed the following labels: " , ' , ' . join ( l [ ' name ' ] for l in labels ) )
2023-10-05 02:44:06 +00:00
# Specifically we aren't going to be getting all the labels for a repo
# with GET /repos/{owner}/{repo}/labels and seeing if our label names
# exist and creating new labels in our new repo with the same name etc
# if they don't with POST /repos/{owner}/{repo}/labels and finally
# assigning all of those new or existing labels to our new issue with
# POST /repos/{owner}/{repo}/issues/{index}/labels
# Note: Labels already removed with pop so we're good on not blowing up.
2023-10-05 02:29:16 +00:00
2023-10-05 01:14:10 +00:00
assignees = json_response . pop ( ' assignees ' , { } )
if assignees :
# 'assignee' is deprecated; remove it.
json_response . pop ( ' assignee ' , None )
# Forgejo's API *gives* us assignee objects but only *accepts* strings.
# Specifically, we need to replace the dict with its 'login' key.
json_response [ ' assignees ' ] = [ ]
for assignee in assignees :
json_response [ ' assignees ' ] . append ( assignee [ ' login ' ] )
2023-10-04 17:49:23 +00:00
print ( f " Creating issue { json_response [ ' title ' ] } now… " )
create_issue_url = API_CREATE_ISSUE . format ( instance = FORGEJO_INSTANCE , owner = destination_owner , repo = destination_repo )
# print(create_issue_url)
headers = { " Authorization " : f " token { FORGEJO_API_TOKEN } " }
2023-10-05 02:17:34 +00:00
created_response = requests . post ( create_issue_url , headers = headers , json = json_response )
2023-10-04 17:49:23 +00:00
json_response = created_response . json ( )
message = json_response . pop ( ' message ' , False )
if message :
print ( message )
2023-10-04 19:46:42 +00:00
sys . exit ( " Error creating issue. " )
2023-10-04 17:49:23 +00:00
else :
2023-10-04 20:19:03 +00:00
new_issue_url = json_response [ ' html_url ' ]
print ( f " Issue created: { new_issue_url } " )
2023-10-04 19:46:42 +00:00
new_issue_number = json_response [ ' number ' ]
print ( f " new_issue_number = { new_issue_number } " )
new_issue_id = json_response [ ' id ' ]
print ( f " new_issue_id = { new_issue_id } " )
print ( f " Moving issue comments. " )
get_comments_url = API_GET_COMMENTS . format ( instance = FORGEJO_INSTANCE , owner = source_owner , repo = source_repo , index = issue_number )
create_comment_url = API_CREATE_COMMENT . format ( instance = FORGEJO_INSTANCE , owner = destination_owner , repo = destination_repo , index = new_issue_number )
comments = requests . get ( get_comments_url , params = { " access_token " : FORGEJO_API_TOKEN } )
json_comments = comments . json ( )
for comment in json_comments :
2023-10-05 02:17:34 +00:00
new_comment = requests . post ( create_comment_url , headers = headers , json = comment )
2023-10-04 19:46:42 +00:00
json_new_comment = new_comment . json ( )
message = json_new_comment . pop ( ' message ' , False )
if message :
print ( message )
sys . exit ( " Error creating comment. " )
2023-10-04 17:49:23 +00:00
2023-10-04 20:19:03 +00:00
moved_to_message = {
' body ' : f " *Issue moved to:* { new_issue_url } "
}
moved_from_message = {
' body ' : f " *Issue moved here from:* { old_issue_url } "
}
2023-10-05 02:17:34 +00:00
new_comment = requests . post ( create_comment_url , headers = headers , json = moved_from_message )
2023-10-04 20:19:03 +00:00
create_old_comment_url = API_CREATE_COMMENT . format ( instance = FORGEJO_INSTANCE , owner = source_owner , repo = source_repo , index = issue_number )
2023-10-05 02:17:34 +00:00
new_old_comment = requests . post ( create_old_comment_url , headers = headers , json = moved_to_message )
2023-10-04 20:19:03 +00:00
2023-10-04 22:26:43 +00:00
# And finally, close the old issue.
# If we are confident the API is remaining stabel we can just use the same path
# with patch, post, and get when the path is the same which is the case here.
# Note though we often change the owner and repo and index when making the URL!
2023-10-05 01:31:13 +00:00
body = {
" state " : " closed "
2023-10-04 22:26:43 +00:00
}
patch_issue_url = API_PATCH_ISSUE . format ( instance = FORGEJO_INSTANCE , owner = source_owner , repo = source_repo , index = issue_number )
2023-10-05 01:32:34 +00:00
# Note that sending body as JSON here is needed for 'state' to be changed.
2023-10-05 01:31:13 +00:00
closed_response = requests . patch ( patch_issue_url , headers = headers , json = body , params = { " access_token " : FORGEJO_API_TOKEN } )
2023-10-04 22:26:43 +00:00
# print(closed_response.json())
2023-10-04 20:19:03 +00:00
2023-10-04 17:49:23 +00:00
if __name__ == " __main__ " :
# '0' comes in as move_issue.py when this is called as `python move_issue.py`
source_owner = sys . argv [ 1 ]
source_repo = sys . argv [ 2 ]
issue_number = sys . argv [ 3 ]
destination_owner = sys . argv [ 4 ]
destination_repo = sys . argv [ 5 ]
move_issue ( source_owner , source_repo , issue_number , destination_owner , destination_repo )