Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion src/hubcast/clients/github/client.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import logging
from urllib.parse import urlparse

import aiohttp
from gidgethub import HTTPException
from gidgethub import aiohttp as gh_aiohttp

from .auth import GitHubAuthenticator

log = logging.getLogger(__name__)

GH_REACTIONS = {
"+1": "THUMBS_UP",
"-1": "THUMBS_DOWN",
Expand Down Expand Up @@ -127,7 +131,18 @@ async def get_repo_config(self):
# get the contents of the repository hubcast.yml file
url = f"/repos/{self.repo_owner}/{self.repo_name}/contents/.github/hubcast.yml"
# get raw contents rather than base64 encoded text
return await gh.getitem(url, accept="application/vnd.github.raw")
try:
return await gh.getitem(url, accept="application/vnd.github.raw")
except HTTPException as exc:
if exc.status_code == 404:
log.info(
"Repo config file not found at .github/hubcast.yml",
extra={
"repo_owner": self.repo_owner,
"repo_name": self.repo_name,
},
)
raise

async def get_pr(self, id):
"""Return individual PR data."""
Expand Down
16 changes: 13 additions & 3 deletions src/hubcast/clients/gitlab/client.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import logging
import urllib.parse
from typing import Dict

import aiohttp
import gidgetlab.aiohttp
import gidgetlab

from .auth import GitLabAuthenticator, GitLabSingleUserAuthenticator

log = logging.getLogger(__name__)


class GitLabClientFactory:
def __init__(
Expand Down Expand Up @@ -84,8 +87,15 @@ async def set_webhook(self, gl_fullname: str, data: Dict):

repo_id = urllib.parse.quote_plus(gl_fullname)
url = f"/projects/{repo_id}/hooks"

hooks_data = await gl.getitem(url)
try:
hooks_data = await gl.getitem(url)
except gidgetlab.exceptions.BadRequest as exc:
if exc.status_code == 403:
log.info(
"User cannot access GitLab webhooks; skipping set_webhook. Must have `maintainer` role.",
extra={"user": self.user, "repo": gl_fullname},
)
return
for hook in hooks_data:
if hook["name"] == "hubcast":
existing_hook = hook
Expand Down
35 changes: 21 additions & 14 deletions src/hubcast/web/github/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,25 @@ async def sync_branch(event, gh, gl, gl_user, *arg, **kwargs):
if await gh.get_prs(branch=target_ref):
return

repo_config = await get_repo_config(gh, src_fullname, refresh=True)
# only refresh config on default branch pushes (where .github/hubcast.yml lives)
default_branch = event.data["repository"]["default_branch"]
is_default_branch = target_ref == f"refs/heads/{default_branch}"
repo_config, fetched = await get_repo_config(
gh, src_fullname, refresh=is_default_branch
)

dest_fullname = f"{repo_config.dest_org}/{repo_config.dest_name}"
dest_remote_url = f"{gl.instance_url}/{dest_fullname}.git"

# setup callback webhook on GitLab
webhook_data = {
"gh_owner": src_owner,
"gh_repo": src_repo_name,
"gh_check": repo_config.check_name,
}
await gl.set_webhook(dest_fullname, webhook_data)
# only set/update webhook on default branch pushes when config cache was bypassed (refresh or initial fetch)
if fetched and is_default_branch:
# setup callback webhook on GitLab
webhook_data = {
"gh_owner": src_owner,
"gh_repo": src_repo_name,
"gh_check": repo_config.check_name,
}
await gl.set_webhook(dest_fullname, webhook_data)
gl_token = await gl.auth.authenticate_user(gl_user)

# sync commits from GitHub -> GitLab
Expand Down Expand Up @@ -113,7 +120,7 @@ async def remove_branch(event, gh, gl, gl_user, *arg, **kwargs):
src_fullname = event.data["repository"]["full_name"]
target_ref = event.data["ref"]

repo_config = await get_repo_config(gh, src_fullname, refresh=True)
repo_config, _ = await get_repo_config(gh, src_fullname)

dest_fullname = f"{repo_config.dest_org}/{repo_config.dest_name}"
dest_remote_url = f"{gl.instance_url}/{dest_fullname}.git"
Expand Down Expand Up @@ -173,7 +180,7 @@ async def sync_pr(pull_request, gh, gl, gl_user, src_repo_private, want_sha):
return

# get the repository configuration from .github/hubcast.yml
repo_config = await get_repo_config(gh, base_fullname)
repo_config, _ = await get_repo_config(gh, base_fullname)
if not repo_config.draft_sync and pull_request["draft"]:
if repo_config.draft_sync_msg:
await gh.set_check_status(
Expand Down Expand Up @@ -274,7 +281,7 @@ async def remove_pr(event, gh, gl, gl_user, *arg, **kwargs):
target_ref = f"refs/heads/pr-{pull_request_id}"

# get the repository configuration from .github/hubcast.yml
repo_config = await get_repo_config(gh, base_fullname)
repo_config, _ = await get_repo_config(gh, base_fullname)

dest_fullname = f"{repo_config.dest_org}/{repo_config.dest_name}"
dest_remote_url = f"{gl.instance_url}/{dest_fullname}.git"
Expand Down Expand Up @@ -352,7 +359,7 @@ async def respond_comment(event, gh, gl, gl_user, *arg, **kwargs):
branch = pull_request["head"]["ref"]

# get the gitlab repo information and run the pipeline
repo_config = await get_repo_config(gh, base_fullname, refresh=True)
repo_config, _ = await get_repo_config(gh, base_fullname)
dest_fullname = f"{repo_config.dest_org}/{repo_config.dest_name}"
pipeline_url = await gl.run_pipeline(dest_fullname, branch)

Expand Down Expand Up @@ -384,7 +391,7 @@ async def respond_comment(event, gh, gl, gl_user, *arg, **kwargs):
branch = pull_request["head"]["ref"]

# get the gitlab repo information and run the pipeline
repo_config = await get_repo_config(gh, base_fullname, refresh=True)
repo_config, _ = await get_repo_config(gh, base_fullname)
dest_fullname = f"{repo_config.dest_org}/{repo_config.dest_name}"
pipeline_id = await gl.get_latest_pipeline(dest_fullname, branch)

Expand Down Expand Up @@ -428,6 +435,6 @@ async def rerun_check(event, gh, gl, gl_user, *arg, **kwargs):
return

# get the GL repo info and run the pipeline
repo_config = await get_repo_config(gh, src_fullname, refresh=True)
repo_config, _ = await get_repo_config(gh, src_fullname)
dest_fullname = f"{repo_config.dest_org}/{repo_config.dest_name}"
await gl.run_pipeline(dest_fullname, branch)
4 changes: 3 additions & 1 deletion src/hubcast/web/github/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def create_config(fullname: str, data: Dict) -> RepoConfig:


async def get_repo_config(gh: GitHubClient, fullname: str, refresh: bool = False):
fetched = False
if fullname in config_cache and not refresh:
config = config_cache[fullname]
else:
Expand All @@ -43,5 +44,6 @@ async def get_repo_config(gh: GitHubClient, fullname: str, refresh: bool = False
)

config_cache[fullname] = config
fetched = True

return config
return config, fetched
Loading