add a script to update issue labels and descriptions (#46)
diff --git a/migration/README.md b/migration/README.md
index f029737..700d864 100644
--- a/migration/README.md
+++ b/migration/README.md
@@ -123,6 +123,17 @@
[2022-07-06 15:35:06,532] INFO:update_issues: Done.
```
+### 7. Update issue labels
+
+`src/update_issue_labels.py` updates issue colors and descriptions.
+
+```
+(.venv) migration $ python src/update_issue_labels.py
+[2022-07-16 09:18:39,764] INFO:update_issue_labels: Retrieving labels.
+[2022-07-16 09:18:42,274] INFO:update_issue_labels: 63 labels are found.
+Done.
+```
+
### How to Generate Account Mapping
This optional step creates Jira username - GitHub account mapping. To associate Jira user with GitHub account, Jira user's "Full Name" and GitHub account's "Name" needs to be set to exactly the same value. See https://github.com/apache/lucene-jira-archive/issues/3.
diff --git a/migration/src/github_issues_util.py b/migration/src/github_issues_util.py
index 14fb12e..e97b97e 100644
--- a/migration/src/github_issues_util.py
+++ b/migration/src/github_issues_util.py
@@ -29,10 +29,10 @@
url = GITHUB_API_BASE + f"/repos/{repo}/issues/{issue_number}"
headers = {"Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json"}
res = requests.get(url, headers=headers)
+ time.sleep(INTERVAL_IN_SECONDS)
if res.status_code != 200:
logger.error(f"Failed to get issue {issue_number}; status_code={res.status_code}, message={res.text}")
return None
- time.sleep(INTERVAL_IN_SECONDS)
return res.json().get("body")
@@ -41,10 +41,10 @@
headers = {"Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json"}
data = {"body": body}
res = requests.patch(url, headers=headers, json=data)
+ time.sleep(INTERVAL_IN_SECONDS)
if res.status_code != 200:
logger.error(f"Failed to update issue {issue_number}; status_code={res.status_code}, message={res.text}")
return False
- time.sleep(INTERVAL_IN_SECONDS)
return True
@@ -57,6 +57,7 @@
while not stop:
url_with_paging = url + f"&page={page}"
res = requests.get(url_with_paging, headers=headers)
+ time.sleep(INTERVAL_IN_SECONDS)
if res.status_code != 200:
logger.error(f"Failed to get issue comments for {issue_number}; status_code={res.status_code}, message={res.text}")
break
@@ -65,7 +66,6 @@
for comment in res.json():
li.append(GHIssueComment(id=comment.get("id"), body=comment.get("body")))
page += 1
- time.sleep(INTERVAL_IN_SECONDS)
return li
@@ -74,10 +74,10 @@
headers = {"Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json"}
data = {"body": body}
res = requests.patch(url, headers=headers, json=data)
+ time.sleep(INTERVAL_IN_SECONDS)
if res.status_code != 200:
logger.error(f"Failed to update comment {comment_id}; status_code={res.status_code}, message={res.text}")
return False
- time.sleep(INTERVAL_IN_SECONDS)
return True
@@ -85,9 +85,9 @@
url = GITHUB_API_BASE + f"/repos/{repo}/import/issues"
headers = {"Authorization": f"token {token}", "Accept": "application/vnd.github.golden-comet-preview+json"}
res = requests.post(url, headers=headers, json=issue_data)
+ time.sleep(INTERVAL_IN_SECONDS)
if res.status_code != 202:
logger.error(f"Failed to import issue {issue_data['issue']['title']}; status_code={res.status_code}, message={res.text}")
- time.sleep(INTERVAL_IN_SECONDS)
return res.json().get("url")
@@ -116,10 +116,10 @@
url = GITHUB_API_BASE + f"/search/users?q={quote_plus(q)}"
headers = {"Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json"}
res = requests.get(url, headers=headers)
+ time.sleep(SEARCH_INTERVAL_IN_SECONDS)
if res.status_code != 200:
logger.error(f"Failed to search users with query {q}; status_code={res.status_code}, message={res.text}")
return []
- time.sleep(SEARCH_INTERVAL_IN_SECONDS)
return [item["login"] for item in res.json()["items"]]
@@ -127,10 +127,10 @@
url = GITHUB_API_BASE + f"/users/{username}"
headers = {"Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json"}
res = requests.get(url, headers=headers)
+ time.sleep(INTERVAL_IN_SECONDS)
if res.status_code != 200:
logger.error(f"Failed to get user {username}; status_code={res.status_code}, message={res.text}")
return None
- time.sleep(INTERVAL_IN_SECONDS)
return res.json()
@@ -141,15 +141,15 @@
users = []
while True:
res = requests.get(f"{url}&page={page}", headers=headers)
- if len(res.json()) == 0:
- break
+ time.sleep(INTERVAL_IN_SECONDS)
if res.status_code != 200:
logger.error(f"Failed to get organization members for {org}; status_code={res.status_code}, message={res.text}")
return users
+ if len(res.json()) == 0:
+ break
users.extend(x["login"] for x in res.json())
logger.debug(f"{len(users)} members found.")
page += 1
- time.sleep(INTERVAL_IN_SECONDS)
return users
@@ -160,17 +160,49 @@
authors = set([])
while True:
res = requests.get(f"{url}&page={page}", headers=headers)
- if len(res.json()) == 0:
- break
+ time.sleep(INTERVAL_IN_SECONDS)
if res.status_code != 200:
logger.error(f"Failed to get commits for {repo}; status_code={res.status_code}, message={res.text}")
return authors
+ if len(res.json()) == 0:
+ break
for commit in res.json():
author = commit.get("author")
if author:
authors.add(author["login"])
logger.debug(f"{len(authors)} authors found.")
page += 1
- time.sleep(INTERVAL_IN_SECONDS)
return authors
+
+def list_labels(token: str, repo: str, logger: Logger) -> list[str]:
+ url = GITHUB_API_BASE + f"/repos/{repo}/labels?per_page=100"
+ headers = {"Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json"}
+ page = 1
+ labels = []
+ while True:
+ res = requests.get(f"{url}&page={page}", headers=headers)
+ time.sleep(INTERVAL_IN_SECONDS)
+ if res.status_code != 200:
+ logger.error(f"Failed to get labels for {repo}; status_code={res.status_code}, message={res.text}")
+ return labels
+ if len(res.json()) == 0:
+ break
+ for l in res.json():
+ name = l["name"]
+ labels.append(name)
+ page += 1
+ return labels
+
+
+def update_label(token: str, repo: str, name: str, color: str, description: str, logger: Logger) -> bool:
+ url = GITHUB_API_BASE + f"/repos/{repo}/labels/{name}"
+ headers = {"Authorization": f"token {token}", "Accept": "application/vnd.github.v3+json"}
+ data = {"color": color, "description": description}
+ res = requests.patch(url, headers=headers, json=data)
+ time.sleep(INTERVAL_IN_SECONDS)
+ if res.status_code != 200:
+ logger.error(f"Failed to update label {name}; status_code={res.status_code}, message={res.text}")
+ return False
+ logger.debug(f"Label {name} updated.")
+ return True
\ No newline at end of file
diff --git a/migration/src/update_issue_labels.py b/migration/src/update_issue_labels.py
new file mode 100644
index 0000000..dfb2f2b
--- /dev/null
+++ b/migration/src/update_issue_labels.py
@@ -0,0 +1,42 @@
+from pathlib import Path
+import os
+import sys
+from common import LOG_DIRNAME, logging_setup
+from github_issues_util import *
+
+log_dir = Path(__file__).resolve().parent.parent.joinpath(LOG_DIRNAME)
+logger = logging_setup(log_dir, "update_issue_labels")
+
+
+# label prefix -> color, description
+LABEL_DETAILS_MAP = {
+ "type:": ("ffbb00", ""),
+ "fixVersion:": ("7ebea5", ""),
+ "affectsVersion:": ("f19072", ""),
+ "component:": ("a0d8ef", "")
+}
+
+
+if __name__ == "__main__":
+ github_token = os.getenv("GITHUB_PAT")
+ if not github_token:
+ print("Please set your GitHub token to GITHUB_PAT environment variable.")
+ sys.exit(1)
+ github_repo = os.getenv("GITHUB_REPO")
+ if not github_repo:
+ print("Please set GitHub repo location to GITHUB_REPO environment varialbe.")
+ sys.exit(1)
+
+ check_authentication(github_token)
+
+ logger.info("Retrieving labels.")
+
+ labels = list_labels(github_token, github_repo, logger)
+ logger.info(f"{len(labels)} labels are found.")
+
+ for label in labels:
+ for prefix, detail in LABEL_DETAILS_MAP.items():
+ if label.startswith(prefix):
+ update_label(github_token, github_repo, label, detail[0], detail[1], logger)
+
+ print("Done.")
\ No newline at end of file