blob: 460114282ac96a3586a8130e4da85bb090d21ac5 [file]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import time
import plugins.basetypes
import plugins.session
import plugins.github
import re
import asfpy.messaging
ADMIN_ADDITIONAL_PROJECTS = ["infrastructure", "members", "board", "foundation"]
EXEC_ADDITIONAL_PROJECTS = ["members", "board", "foundation"]
""" GitHub/GitBox default branch mgmt endpoint for Boxer """
async def process(
server: plugins.basetypes.Server, session: plugins.session.SessionObject, indata: dict
) -> dict:
if not session.credentials:
return {"okay": False, "message": "You need to be logged in to access this endpoint."}
new_default_branch = indata.get("default_branch")
if not new_default_branch:
return {"okay": False, "message": "Invalid branch name specified."}
# Ensure repo exists
repo = indata.get("repository")
repo_filepath = None
for _repo in server.data.repositories:
if _repo.filename == repo:
repo_filepath = _repo.filepath
break
if not repo_filepath:
return {"okay": False, "message": "Invalid repository specified."}
# Ensure right permissions
m = re.match(r"^(?:incubator-|terraform-provider-)?([a-z0-9]+)(-[-0-9a-z]+)?(\.git)?$", repo) # httpd.git or sling-foo.git etc
if not m:
return {"okay": False, "message": "Invalid repository name specified"}
pmc = m.group(1)
# TODO: use oauth.a.o data object instead of LDAP lookups
if not session.credentials.admin and not (session.credentials.member and pmc in EXEC_ADDITIONAL_PROJECTS):
async with plugins.ldap.LDAPClient(server.config.ldap) as lc:
committer_list, pmc_list = await lc.get_members(pmc)
if not pmc_list:
return {"okay": False, "message": "Invalid project prefix '%s' specified" % pmc}
if session.credentials.uid not in pmc_list:
return {"okay": False, "message": "Only (I)PMC members of this project may change the default branch of a repository"}
# Change default on GitHub:
asf_github_org = plugins.github.GitHubOrganisation(
login=server.config.github.org, personal_access_token=server.config.github.token
)
try:
await asf_github_org.get_id() # Must be called in order to elevate access.
await asf_github_org.api_patch(f"https://api.github.com/repos/{server.config.github.org}/{repo}", {"default_branch": new_default_branch})
except AssertionError as e:
return {"okay": False, "message": "Could not archive repository on GitHub."}
# Change default on gitbox (override the repo.git/HEAD file):
with open(os.path.join(repo_filepath, "HEAD"), "w") as f:
f.write(f"ref: refs/heads/{new_default_branch}")
f.close()
# Send notification to project
asfpy.messaging.mail(
sender="GitBox <gitbox@apache.org>",
recipients=[f"private@{pmc}.apache.org"],
subject=f"Repository default branch changed for: {repo}",
message=f"User {session.credentials.email} changed the default branch of {repo} to: {new_default_branch}\n"
)
return {"okay": True, "message": f"Repository default branch successfully updated to {new_default_branch}."}
def register(server: plugins.basetypes.Server):
return plugins.basetypes.Endpoint(process)