227 lines
8.4 KiB
Python

import os
import sys
import time
import json
import zipfile
import datetime
import subprocess
from allspice import AllSpice, DesignReview, Repository
from argparse import ArgumentParser
###############################################################################
GET_LAST_COMMIT_ON_DRAGDROP_ENDPOINT = """/repos/{owner}/{repo}/commits?sha={ref}&limit=1"""
GET_LATEST_DESIGN_REVIEW_ENDPOINT = """/repos/{owner}/{repo}/pulls/{base}/{head}"""
MERGE_DESIGN_REVIEW_ENDPOINT = """/repos/{owner}/{repo}/pulls/{index}/merge"""
###############################################################################
def extract_newly_added_zip_files(newly_added_zip_files):
print("- Extracting newly added zip files:")
# Extract the archives
for filepath in newly_added_zip_files:
with zipfile.ZipFile(filepath, "r") as zipper:
print(" > " + filepath)
zipper.extractall("./" + os.path.dirname(filepath))
# Delete the newly added zip files
os.remove(filepath)
###############################################################################
def get_new_zip_files_added_in_previous_commit():
git_log_output = subprocess.check_output(
["git log --name-status -1"], shell=True, encoding="utf-8"
)
git_log_filepaths = git_log_output.splitlines()[6:]
newly_added_files = []
for file in git_log_filepaths:
if file[0] == "A":
newly_added_files.append(file[2:])
newly_added_zip_files = [
file for file in newly_added_files if file.endswith(".zip")
]
return newly_added_zip_files
###############################################################################
def push_changes_on_dragdrop_branch(ref):
# Add files for commit
git_add_output = subprocess.check_output(
["git add ."], shell=True, encoding="utf-8"
)
# Add a commit message
git_commit_output = subprocess.check_output(
['git commit -m "Unpacked archives from commit ' + sha[0:10] + '"'],
shell=True,
encoding="utf-8",
)
# Push to remote
print("- Pushing extracted files to the '" + ref + "' branch")
git_push_process = subprocess.run(
"git push", capture_output=True, text=True, shell=True
)
###############################################################################
def set_git_config(name, email):
git_config_name_output = subprocess.check_output(
["git config --global user.name " + '"' + name + '"'],
shell=True,
encoding="utf-8",
)
git_config_email_output = subprocess.check_output(
["git config --global user.email " + '"' + email + '"'],
shell=True,
encoding="utf-8",
)
###############################################################################
def get_previous_commit_on_dragdrop_branch(client, repository, auth_token, ref):
time.sleep(0.1)
commits_json = client.requests_get(
GET_LAST_COMMIT_ON_DRAGDROP_ENDPOINT.format(
owner=repository.owner.username, repo=repository.name, token=auth_token, ref=ref
)
)
# Set author as the same person who made the previous commit
name = commits_json[0]["commit"]["committer"]["name"]
email = commits_json[0]["commit"]["committer"]["email"]
sha = commits_json[0]["sha"]
return name, email, sha
###############################################################################
def get_latest_design_review_dragdrop_to_develop(client, repository, ref):
time.sleep(0.1)
dr_json = client.requests_get(
GET_LATEST_DESIGN_REVIEW_ENDPOINT.format(
owner=repository.owner.username,
repo=repository.name,
base="develop",
head=ref,
)
)
# Get the latest DR
time.sleep(0.1)
dr = DesignReview.request(
allspice,
repository.owner.username,
repository.name,
str(dr_json["number"]),
)
return dr
###############################################################################
def merge_design_review(client, repository, dr):
retries = 1
merged = False
while not merged and retries < 6:
try:
time.sleep(0.1)
client.requests_post(
MERGE_DESIGN_REVIEW_ENDPOINT.format(
owner=repository.owner.username,
repo=repository.name,
index=dr.number,
),
data={"Do": "merge"},
)
merged = True
except Exception:
print("- Merge failed. Trying again in ", end="")
for t in range(0, 5, -1):
print(str(t) + "...")
print(" " + str(5 - retries) + " retries left", end="", flush=True)
time.sleep(5)
retries += 1
###############################################################################
def create_and_merge_design_review(client, repository, ref):
print("- Creating new design review...")
try:
dr = repository.create_design_review(
title="Automated merge on "
+ datetime.datetime.now().strftime("%Y-%m-%d @ %H:%M"),
head=ref,
base="develop",
)
print("- Design review #" + str(dr.number) + " created")
except allspice.exceptions.AlreadyExistsException:
dr = get_latest_design_review_dragdrop_to_develop(client, repository)
print("- Design review # " + str(dr.number) + " already exists")
# Merge the design review
print("- Merging design review " + ref + "->develop")
merge_design_review(client, repository, dr)
###############################################################################
if __name__ == "__main__":
# Initialize argument parser
parser = ArgumentParser()
parser.add_argument("repository", help="Repository object for the target repo")
parser.add_argument(
"--allspice_hub_url",
help="The URL of your AllSpice Hub instance. Defaults to https://hub.allspice.io.",
)
parser.add_argument(
"--dragdrop_branch_name",
help="Name of the drag-n-drop branch"
)
parser.add_argument(
"--unzip_new_archives",
help="Newly added zip files will be unzipped if this option is set",
action="store_true",
)
parser.add_argument(
"--upload_method_branch",
help="Newly added zip files will be unzipped if this option is set",
action="store_true",
)
parser.add_argument(
"--upload_method_issue",
help="Newly added zip files will be unzipped if this option is set",
action="store_true",
)
args = parser.parse_args()
# Can't use both issues and branches for uploads simultaneously
if args.upload_method_branch and args.upload_method_issue:
print(
"Cannot use branch file upload and issue attachment upload simultaneously. Choose either --upload_method_branch OR --upload_method_issue."
)
exit(1)
# Get auth token and hub url
auth_token = os.environ.get("ALLSPICE_AUTH_TOKEN")
if auth_token is None:
print("Please set the environment variable ALLSPICE_AUTH_TOKEN")
exit(1)
if args.allspice_hub_url is None:
allspice = AllSpice(token_text=auth_token)
else:
allspice = AllSpice(
token_text=auth_token,
allspice_hub_url=args.allspice_hub_url,
)
# Get the repository
repo_owner, repo_name = args.repository.split("/")
repository = allspice.get_repository(repo_owner, repo_name)
# If unzip_new_archives option is specified, unzip newly added archives
if args.unzip_new_archives:
# Get filepaths to any newly added zip files in the previous commmit
newly_added_zip_files = get_new_zip_files_added_in_previous_commit()
# Process extracting
if newly_added_zip_files:
# Extract and remove newly added zip files
extract_newly_added_zip_files(newly_added_zip_files)
# Get the previous commit
name, email, sha = get_previous_commit_on_dragdrop_branch(allspice, repository, auth_token, args.dragdrop_branch_name)
# Set git config user and email
set_git_config(name, email)
# Push changes to the drag-n-drop branch
push_changes_on_dragdrop_branch(args.dragdrop_branch_name)
# Create a design review to merge from drag-n-drop to develop branch
create_and_merge_design_review(allspice, repository, args.dragdrop_branch_name)