diff --git a/bridge/__init__.py b/bridge/__init__.py
index 9a3f26f..14ff785 100644
--- a/bridge/__init__.py
+++ b/bridge/__init__.py
@@ -27,7 +27,10 @@ def gitea_handle_repo_action():
Gitea and Github ends
"""
- gitea = Gitea(app.config["GITEA_ACCESS_TOKEN"])
+ gitea = Gitea(
+ api_token=app.config["GITEA_ACCESS_TOKEN"],
+ instance_name=app.config["GITEA_INSTANCE_DOMAIN"]
+ )
github = Github(app.config["GITHUB_ACCESS_TOKEN"])
data = request.json
@@ -47,94 +50,38 @@ def gitea_handle_repo_action():
if not repo_action == "created":
return ''
- github_created_repo_result = github.post(
- "https://api.github.com/user/repos",
- json={
- "name": repo_name,
- "description": repo_description,
- "homepage": "https://{}/{}/{}".format(
- app.config["GITEA_INSTANCE_DOMAIN"],
- repo_owner,
- repo_name,
- ),
- },
+ github_created_repo_result = github.create_repo(
+ repo_name, repo_description
)
new_github_repo_url = github_created_repo_result.json()["html_url"]
- gitea_add_github_repo_url_result = gitea.patch(
- "https://{}/api/v1/repos/{}/{}".format(
- app.config["GITEA_INSTANCE_DOMAIN"],
- repo_owner,
- repo_name,
- ),
- json={
- "website": new_github_repo_url,
- },
+ gitea_push_target_result = gitea.add_push_target(
+ repo_owner, repo_name, new_github_repo_url, repo_owner,
+ app.config["GITHUB_ACCESS_TOKEN"]
)
- gitea_push_target_result = gitea.post(
- "https://{}/api/v1/repos/{}/{}/push_mirrors".format(
- app.config["GITEA_INSTANCE_DOMAIN"],
- repo_owner,
- repo_name
- ),
- json={
- "interval": "8h0m0s",
- "remote_address": new_github_repo_url,
- "remote_password": app.config["GITHUB_ACCESS_TOKEN"],
- "remote_username": repo_owner,
- "sync_on_commit": True,
- },
+ gitea_force_target_push = gitea.force_push_target(
+ repo_owner,
+ repo_name
)
- gitea_force_target_push = gitea.post(
- "https://{}/api/v1/repos/{}/{}/push_mirrors-sync".format(
- app.config["GITEA_INSTANCE_DOMAIN"],
- repo_owner,
- repo_name
+ github_create_webhook_result = github.create_webhook(
+ repo_owner,
+ repo_name,
+ "https://{}/bridge/endpoints/github/issue".format(
+ app.config["GITEA_INSTANCE_DOMAIN"]
),
+ ["issues", "issue_comment"]
)
- github_create_webhook_result = github.post(
- "https://api.github.com/repos/{}/{}/hooks".format(
- repo_owner,
- repo_name,
+ gitea_create_webhook_result = gitea.create_webhook(
+ repo_owner,
+ repo_name,
+ "https://{}/bridge/endpoints/gitea/issue".format(
+ app.config["GITEA_INSTANCE_DOMAIN"]
),
- json={
- "name": "web",
- "config": {
- "url": "https://{}/bridge/endpoints/github/issue".format(
- app.config["GITEA_INSTANCE_DOMAIN"]
- ),
- "content_type": "json",
- },
- "events": [
- "issues", "issue_comment",
- ],
- },
- )
-
- gitea_create_webhook_result = gitea.post(
- "https://{}/api/v1/repos/{}/{}/hooks".format(
- app.config["GITEA_INSTANCE_DOMAIN"],
- repo_owner,
- repo_name,
- ),
- json={
- "active": True,
- "type": "gitea",
- "config": {
- "content_type": "json",
- "url": "https://{}/bridge/endpoints/gitea/issue".format(
- app.config["GITEA_INSTANCE_DOMAIN"],
- ),
- "http_method": "post",
- },
- "events": [
- "issues", "issue_comment",
- ],
- },
+ ["issues", "issue_comment"]
)
return ''
@@ -157,7 +104,10 @@ def gitea_handle_issue_action():
- add a cooresponding comment and close the Github issue
"""
- gitea = Gitea(app.config["GITEA_ACCESS_TOKEN"])
+ gitea = Gitea(
+ api_token=app.config["GITEA_ACCESS_TOKEN"],
+ instance_name=app.config["GITEA_INSTANCE_DOMAIN"]
+ )
github = Github(app.config["GITHUB_ACCESS_TOKEN"])
data = request.json
@@ -214,15 +164,11 @@ def gitea_handle_issue_action():
issue_footer
])
- github_create_issue_result = github.post(
- "https://api.github.com/repos/{}/{}/issues".format(
- repo_owner,
- repo_name,
- ),
- json={
- "title": event_title,
- "body": issue_body,
- },
+ github_create_issue_result = github.create_issue(
+ repo_owner,
+ repo_name,
+ event_title,
+ issue_body,
)
returned_data = github_create_issue_result.json()
@@ -239,16 +185,11 @@ def gitea_handle_issue_action():
generate_sentinel(returned_data["url"])
)
- gitea_issue_comment_result = gitea.post(
- "https://{}/api/v1/repos/{}/{}/issues/{}/comments".format(
- app.config["GITEA_INSTANCE_DOMAIN"],
- repo_owner,
- repo_name,
- issue_number,
- ),
- json={
- "body": issue_comment_body,
- },
+ gitea_issue_comment_result = gitea.leave_comment_on_issue_by_number(
+ repo_owner,
+ repo_name,
+ issue_number,
+ body,
)
elif event_type == "created":
@@ -277,27 +218,129 @@ def gitea_handle_issue_action():
comment_footer,
])
- github_comment_post_result = github.post(
- "https://api.github.com/repos/{}/{}/issues/{}/comments".format(
- repo_owner,
- repo_name,
- issue_number,
- ),
- json={
- "body": comment_body,
- },
+ github_comment_post_result = github.leave_comment_on_issue_by_number(
+ repo_owner,
+ repo_name,
+ issue_number,
+ body,
)
elif event_type == "closed":
- github_close_issue_result = github.patch(
- "https://api.github.com/repos/{}/{}/issues/{}".format(
- repo_owner,
- repo_name,
- issue_number,
- ),
- json={
- "state": "closed",
- },
+ github_close_issue_result = github.close_issue_by_number(
+ repo_owner,
+ repo_name,
+ issue_number,
)
- return ''
\ No newline at end of file
+ return ''
+
+@app.route("/bridge/endpoints/github/issue", methods=["POST"])
+def github_handle_issue_action():
+ gitea = Gitea(
+ api_token=app.config["GITEA_ACCESS_TOKEN"],
+ instance_name=app.config["GITEA_INSTANCE_DOMAIN"]
+ )
+ github = Github(app.config["GITHUB_ACCESS_TOKEN"])
+
+ data = request.json
+
+ try:
+ event_type = data["action"]
+
+ repo_owner = data["repository"]["owner"]["login"]
+ repo_name = data["repository"]["name"]
+ issue_user = data["issue"]["user"]["login"]
+ issue_user_url = "https://github.com/{}".format(
+ issue_user,
+ )
+ issue_number = data["issue"]["number"]
+
+ if event_type == "opened": # new issue created
+ event_title = data["issue"]["title"]
+ event_body = data["issue"]["body"]
+ elif event_type == "created": # new comment on that issue
+ event_title = None
+ event_body = data["comment"]["body"]
+ elif event_type == "closed": # issue closed
+ event_title = None
+ event_body = data["issue"]["body"]
+
+ if not event_body: event_body = ""
+ event_url = data["issue"]["url"]
+
+ except KeyError as e:
+ print(e, type(e))
+ abort(400) # the data isn't formatted correctly
+
+ if issue_sentinel in event_body:
+ return ''
+
+ if event_type == "opened":
+ issue_header = "*This issue has automatically been created by [`gitea-github-sync`](https://{}/bridge/about) on behalf of [{}]({}).*".format(
+ app.config["GITEA_INSTANCE_DOMAIN"],
+ issue_user,
+ issue_user_url,
+ )
+
+ issue_footer = """
+
+ Internal issue metadata
+
+ {}
+
+ """.format(generate_sentinel(event_url))
+
+ issue_body = "\n\n".join([
+ issue_header,
+ event_body,
+ issue_footer
+ ])
+
+ gitea_create_issue_result = gitea.create_issue(
+ repo_owner,
+ repo_name,
+ event_title,
+ issue_body
+ )
+
+ elif event_type == "created":
+ comment_user = data["comment"]["user"]["login"]
+ comment_user_url = "https://github.com/{}".format(
+ comment_user,
+ )
+ comment_header = "*This comment has automatically been created by [`gitea-github-sync`](https://{}/bridge/about) on behalf of [{}]({}).*".format(
+ app.config["GITEA_INSTANCE_DOMAIN"],
+ comment_user,
+ comment_user_url,
+ )
+
+ comment_footer = """
+
+ Internal issue metadata
+
+ {}
+
+ """.format(generate_sentinel(event_url))
+
+ comment_body = "\n\n".join([
+ comment_header,
+ event_body,
+ comment_footer,
+ ])
+
+
+ gitea_comment_post_result = gitea.leave_comment_on_issue_by_number(
+ repo_owner,
+ repo_name,
+ issue_number,
+ comment_body
+ )
+
+ elif event_type == "closed":
+ gitea_close_issue_result = gitea.close_issue_by_number(
+ repo_owner,
+ repo_name,
+ issue_number,
+ )
+
+ return ''
diff --git a/bridge/webgit.py b/bridge/webgit.py
index 3b6a099..2d273ad 100644
--- a/bridge/webgit.py
+++ b/bridge/webgit.py
@@ -15,6 +15,7 @@ class WebgitClient:
"""
api_token: str
headers: Any = field(init=False)
+ api_prefix: str = field(init=False)
def _post_request(self, request_obj):
try:
@@ -42,6 +43,67 @@ class WebgitClient:
def patch(self, *args, **kwargs):
return self._request_wrapper("PATCH", *args, **kwargs)
+ def create_repo(self, name, description):
+ return self.post(
+ self.api_prefix + "/user/repos",
+ json={
+ "name": name,
+ "description": description,
+ },
+ )
+
+ def create_issue(self, owner, repo_name, title, body):
+ return self.post(
+ self.api_prefix + "/repos/{}/{}/issues".format(
+ owner,
+ repo_name,
+ ),
+ json={
+ "title": title,
+ "body": body,
+ },
+ )
+
+ def leave_comment_on_issue_by_number(self, owner, repo_name, issue_number, body):
+ return self.post(
+ self.api_prefix + "/repos/{}/{}/issues/{}/comments".format(
+ owner,
+ repo_name,
+ issue_number,
+ ),
+ json={
+ "body": body,
+ },
+ )
+
+ def leave_comment_on_issue_by_url(self, url, body):
+ return self.post(
+ url + "/comments",
+ json={
+ "body": body,
+ },
+ )
+
+ def close_issue_by_number(self, owner, repo_name, issue_number):
+ return self.patch(
+ self.api_prefix + "/repos/{}/{}/issues/{}".format(
+ owner,
+ repo_name,
+ issue_number,
+ ),
+ json={
+ "state": "closed",
+ },
+ )
+
+ def close_issue_by_url(self, url):
+ return self.patch(
+ url,
+ json={
+ "state": "closed",
+ },
+ )
+
@dataclass
class Github(WebgitClient):
"""
@@ -53,13 +115,71 @@ class Github(WebgitClient):
"Authorization": "token " + self.api_token,
"X-GitHub-Api-Version": "2022-11-28",
}
+ self.api_prefix = "https://api.github.com"
+
+ def create_webhook(self, owner, repo_name, http_endpoint, events: list[str]):
+ return self.post(
+ self.api_prefix + "/repos/{}/{}/hooks".format(
+ owner,
+ repo_name,
+ ),
+ json={
+ "name": "web",
+ "config": {
+ "url": http_endpoint,
+ "content_type": "json",
+ },
+ "events": events,
+ },
+ )
@dataclass
class Gitea(WebgitClient):
"""
A quite thin wrapper around Gitea's REST API.
"""
+ instance_name: str
+
def __post_init__(self):
self.headers = {
"Authorization": "token " + self.api_token,
}
+ self.api_prefix = "https://{}/api/v1".format(self.instance_name)
+
+ def add_push_target(self, owner, repo_name, address, username, password):
+ return self.post(
+ self.api_prefix + "/repos/{}/{}/push_mirrors".format(
+ owner, repo_name
+ ),
+ json={
+ "interval": "8h0m0s",
+ "remote_address": address,
+ "remote_password": password,
+ "remote_username": username,
+ "sync_on_commit": True,
+ },
+ )
+
+ def force_push_target(self, owner, repo_name):
+ return self.post(
+ self.api_prefix + "/repos/{}/{}/push_mirrors-sync".format(
+ owner,
+ repo_name
+ ),
+ )
+
+ def create_webhook(self, owner, repo_name, http_endpoint, events: list[str]):
+ return self.post(
+ self.api_prefix + "/repos/{}/{}/hooks".format(
+ owner,
+ repo_name,
+ ),
+ json={
+ "config": {
+ "url": http_endpoint,
+ "content_type": "json",
+ },
+ "events": events,
+ "type": "gitea",
+ },
+ )