Remove python related code and artifacts
This commit is contained in:
parent
4ba9ca3d10
commit
803cc5ea8a
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,6 +1,3 @@
|
||||||
__pycache__
|
|
||||||
.python-version
|
|
||||||
|
|
||||||
lib/
|
lib/
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
|
|
48
dist/cpr/common.py
vendored
48
dist/cpr/common.py
vendored
|
@ -1,48 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
import random
|
|
||||||
import re
|
|
||||||
import string
|
|
||||||
|
|
||||||
|
|
||||||
def get_random_string(length=7, chars=string.ascii_lowercase + string.digits):
|
|
||||||
return "".join(random.choice(chars) for _ in range(length))
|
|
||||||
|
|
||||||
|
|
||||||
def parse_github_repository(url):
|
|
||||||
# Parse the protocol and github repository from a URL
|
|
||||||
# e.g. HTTPS, peter-evans/create-pull-request
|
|
||||||
https_pattern = re.compile(r"^https://.*@?github.com/(.+/.+)$")
|
|
||||||
ssh_pattern = re.compile(r"^git@github.com:(.+/.+).git$")
|
|
||||||
|
|
||||||
match = https_pattern.match(url)
|
|
||||||
if match is not None:
|
|
||||||
return "HTTPS", match.group(1)
|
|
||||||
|
|
||||||
match = ssh_pattern.match(url)
|
|
||||||
if match is not None:
|
|
||||||
return "SSH", match.group(1)
|
|
||||||
|
|
||||||
raise ValueError(f"The format of '{url}' is not a valid GitHub repository URL")
|
|
||||||
|
|
||||||
|
|
||||||
def parse_display_name_email(display_name_email):
|
|
||||||
# Parse the name and email address from a string in the following format
|
|
||||||
# Display Name <email@address.com>
|
|
||||||
pattern = re.compile(r"^([^<]+)\s*<([^>]+)>$")
|
|
||||||
|
|
||||||
# Check we have a match
|
|
||||||
match = pattern.match(display_name_email)
|
|
||||||
if match is None:
|
|
||||||
raise ValueError(
|
|
||||||
f"The format of '{display_name_email}' is not a valid email address with display name"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check that name and email are not just whitespace
|
|
||||||
name = match.group(1).strip()
|
|
||||||
email = match.group(2).strip()
|
|
||||||
if len(name) == 0 or len(email) == 0:
|
|
||||||
raise ValueError(
|
|
||||||
f"The format of '{display_name_email}' is not a valid email address with display name"
|
|
||||||
)
|
|
||||||
|
|
||||||
return name, email
|
|
145
dist/cpr/create_or_update_branch.py
vendored
145
dist/cpr/create_or_update_branch.py
vendored
|
@ -1,145 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
""" Create or Update Branch """
|
|
||||||
import common as cmn
|
|
||||||
from git import Repo, GitCommandError
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
CHERRYPICK_EMPTY = (
|
|
||||||
"The previous cherry-pick is now empty, possibly due to conflict resolution."
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_successful(repo, repo_url, branch):
|
|
||||||
try:
|
|
||||||
repo.git.fetch(repo_url, f"{branch}:refs/remotes/origin/{branch}")
|
|
||||||
except GitCommandError:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def is_ahead(repo, branch_1, branch_2):
|
|
||||||
# Return true if branch_2 is ahead of branch_1
|
|
||||||
return (
|
|
||||||
int(repo.git.rev_list("--right-only", "--count", f"{branch_1}...{branch_2}"))
|
|
||||||
> 0
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def is_behind(repo, branch_1, branch_2):
|
|
||||||
# Return true if branch_2 is behind branch_1
|
|
||||||
return (
|
|
||||||
int(repo.git.rev_list("--left-only", "--count", f"{branch_1}...{branch_2}")) > 0
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def is_even(repo, branch_1, branch_2):
|
|
||||||
# Return true if branch_2 is even with branch_1
|
|
||||||
return not is_ahead(repo, branch_1, branch_2) and not is_behind(
|
|
||||||
repo, branch_1, branch_2
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def has_diff(repo, branch_1, branch_2):
|
|
||||||
diff = repo.git.diff(f"{branch_1}..{branch_2}")
|
|
||||||
return len(diff) > 0
|
|
||||||
|
|
||||||
|
|
||||||
def create_or_update_branch(repo, repo_url, commit_message, base, branch):
|
|
||||||
# Set the default return values
|
|
||||||
action = "none"
|
|
||||||
diff = False
|
|
||||||
|
|
||||||
# Get the working base. This may or may not be the actual base.
|
|
||||||
working_base = repo.git.symbolic_ref("HEAD", "--short")
|
|
||||||
# If the base is not specified it is assumed to be the working base
|
|
||||||
if base is None:
|
|
||||||
base = working_base
|
|
||||||
|
|
||||||
# Save the working base changes to a temporary branch
|
|
||||||
temp_branch = cmn.get_random_string(length=20)
|
|
||||||
repo.git.checkout("HEAD", b=temp_branch)
|
|
||||||
# Commit any uncomitted changes
|
|
||||||
if repo.is_dirty(untracked_files=True):
|
|
||||||
print(f"Uncommitted changes found. Adding a commit.")
|
|
||||||
repo.git.add("-A")
|
|
||||||
repo.git.commit(m=commit_message)
|
|
||||||
|
|
||||||
# Perform fetch and reset the working base
|
|
||||||
# Commits made during the workflow will be removed
|
|
||||||
repo.git.fetch("--force", repo_url, f"{working_base}:{working_base}")
|
|
||||||
|
|
||||||
# If the working base is not the base, rebase the temp branch commits
|
|
||||||
if working_base != base:
|
|
||||||
print(
|
|
||||||
f"Rebasing commits made to branch '{working_base}' on to base branch '{base}'"
|
|
||||||
)
|
|
||||||
# Checkout the actual base
|
|
||||||
repo.git.fetch("--force", repo_url, f"{base}:{base}")
|
|
||||||
repo.git.checkout(base)
|
|
||||||
# Cherrypick commits from the temporary branch starting from the working base
|
|
||||||
commits = repo.git.rev_list("--reverse", f"{working_base}..{temp_branch}", ".")
|
|
||||||
for commit in commits.splitlines():
|
|
||||||
try:
|
|
||||||
repo.git.cherry_pick(
|
|
||||||
"--strategy",
|
|
||||||
"recursive",
|
|
||||||
"--strategy-option",
|
|
||||||
"theirs",
|
|
||||||
f"{commit}",
|
|
||||||
)
|
|
||||||
except GitCommandError as e:
|
|
||||||
if CHERRYPICK_EMPTY not in e.stderr:
|
|
||||||
print("Unexpected error: ", e)
|
|
||||||
raise
|
|
||||||
# Reset the temp branch to the working index
|
|
||||||
repo.git.checkout("-B", temp_branch, "HEAD")
|
|
||||||
# Reset the base
|
|
||||||
repo.git.fetch("--force", repo_url, f"{base}:{base}")
|
|
||||||
|
|
||||||
# Try to fetch the pull request branch
|
|
||||||
if not fetch_successful(repo, repo_url, branch):
|
|
||||||
# The pull request branch does not exist
|
|
||||||
print(f"Pull request branch '{branch}' does not exist yet")
|
|
||||||
# Create the pull request branch
|
|
||||||
repo.git.checkout("HEAD", b=branch)
|
|
||||||
# Check if the pull request branch is ahead of the base
|
|
||||||
diff = is_ahead(repo, base, branch)
|
|
||||||
if diff:
|
|
||||||
action = "created"
|
|
||||||
print(f"Created branch '{branch}'")
|
|
||||||
else:
|
|
||||||
print(
|
|
||||||
f"Branch '{branch}' is not ahead of base '{base}' and will not be created"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# The pull request branch exists
|
|
||||||
print(
|
|
||||||
f"Pull request branch '{branch}' already exists as remote branch 'origin/{branch}'"
|
|
||||||
)
|
|
||||||
# Checkout the pull request branch
|
|
||||||
repo.git.checkout(branch)
|
|
||||||
|
|
||||||
if has_diff(repo, branch, temp_branch):
|
|
||||||
# If the branch differs from the recreated temp version then the branch is reset
|
|
||||||
# For changes on base this action is similar to a rebase of the pull request branch
|
|
||||||
print(f"Resetting '{branch}'")
|
|
||||||
repo.git.checkout("-B", branch, temp_branch)
|
|
||||||
# repo.git.switch("-C", branch, temp_branch)
|
|
||||||
|
|
||||||
# Check if the pull request branch has been updated
|
|
||||||
# If the branch was reset or updated it will be ahead
|
|
||||||
# It may be behind if a reset now results in no diff with the base
|
|
||||||
if not is_even(repo, f"origin/{branch}", branch):
|
|
||||||
action = "updated"
|
|
||||||
print(f"Updated branch '{branch}'")
|
|
||||||
else:
|
|
||||||
print(f"Branch '{branch}' is even with its remote and will not be updated")
|
|
||||||
|
|
||||||
# Check if the pull request branch is ahead of the base
|
|
||||||
diff = is_ahead(repo, base, branch)
|
|
||||||
|
|
||||||
# Delete the temporary branch
|
|
||||||
repo.git.branch("--delete", "--force", temp_branch)
|
|
||||||
|
|
||||||
return {"action": action, "diff": diff, "base": base}
|
|
162
dist/cpr/create_or_update_pull_request.py
vendored
162
dist/cpr/create_or_update_pull_request.py
vendored
|
@ -1,162 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
""" Create or Update Pull Request """
|
|
||||||
from github import Github, GithubException
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
def string_to_bool(str):
|
|
||||||
if str is None:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return str.lower() in [
|
|
||||||
"true",
|
|
||||||
"1",
|
|
||||||
"t",
|
|
||||||
"y",
|
|
||||||
"yes",
|
|
||||||
"on",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def cs_string_to_list(str):
|
|
||||||
# Split the comma separated string into a list
|
|
||||||
l = [i.strip() for i in str.split(",")]
|
|
||||||
# Remove empty strings
|
|
||||||
return list(filter(None, l))
|
|
||||||
|
|
||||||
|
|
||||||
def create_project_card(github_repo, project_name, project_column_name, pull_request):
|
|
||||||
# Locate the project by name
|
|
||||||
project = None
|
|
||||||
for project_item in github_repo.get_projects("all"):
|
|
||||||
if project_item.name == project_name:
|
|
||||||
project = project_item
|
|
||||||
break
|
|
||||||
|
|
||||||
if not project:
|
|
||||||
print("::error::Project not found. Unable to create project card.")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Locate the column by name
|
|
||||||
column = None
|
|
||||||
for column_item in project.get_columns():
|
|
||||||
if column_item.name == project_column_name:
|
|
||||||
column = column_item
|
|
||||||
break
|
|
||||||
|
|
||||||
if not column:
|
|
||||||
print("::error::Project column not found. Unable to create project card.")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Create a project card for the pull request
|
|
||||||
column.create_card(content_id=pull_request.id, content_type="PullRequest")
|
|
||||||
print(
|
|
||||||
"Added pull request #%d to project '%s' under column '%s'"
|
|
||||||
% (pull_request.number, project.name, column.name)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def create_or_update_pull_request(
|
|
||||||
github_token,
|
|
||||||
github_repository,
|
|
||||||
branch,
|
|
||||||
base,
|
|
||||||
title,
|
|
||||||
body,
|
|
||||||
labels,
|
|
||||||
assignees,
|
|
||||||
milestone,
|
|
||||||
reviewers,
|
|
||||||
team_reviewers,
|
|
||||||
project_name,
|
|
||||||
project_column_name,
|
|
||||||
draft,
|
|
||||||
request_to_parent,
|
|
||||||
):
|
|
||||||
github_repo = head_repo = Github(github_token).get_repo(github_repository)
|
|
||||||
if string_to_bool(request_to_parent):
|
|
||||||
github_repo = github_repo.parent
|
|
||||||
if github_repo is None:
|
|
||||||
raise ValueError(
|
|
||||||
"The checked out repository is not a fork. Input 'request-to-parent' should be set to false."
|
|
||||||
)
|
|
||||||
|
|
||||||
head_branch = f"{head_repo.owner.login}:{branch}"
|
|
||||||
|
|
||||||
# Create the pull request
|
|
||||||
try:
|
|
||||||
pull_request = github_repo.create_pull(
|
|
||||||
title=title,
|
|
||||||
body=body,
|
|
||||||
base=base,
|
|
||||||
head=head_branch,
|
|
||||||
draft=string_to_bool(draft),
|
|
||||||
)
|
|
||||||
print(
|
|
||||||
f"Created pull request #{pull_request.number} ({head_branch} => {github_repo.owner.login}:{base})"
|
|
||||||
)
|
|
||||||
except GithubException as e:
|
|
||||||
if e.status == 422:
|
|
||||||
# A pull request exists for this branch and base
|
|
||||||
# Get the pull request
|
|
||||||
pull_request = github_repo.get_pulls(
|
|
||||||
state="open", base=base, head=head_branch
|
|
||||||
)[0]
|
|
||||||
# Update title and body
|
|
||||||
pull_request.as_issue().edit(title=title, body=body)
|
|
||||||
print(
|
|
||||||
f"Updated pull request #{pull_request.number} ({head_branch} => {github_repo.owner.login}:{base})"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
print(str(e))
|
|
||||||
raise
|
|
||||||
|
|
||||||
# Set the output variables
|
|
||||||
os.system(f"echo ::set-env name=PULL_REQUEST_NUMBER::{pull_request.number}")
|
|
||||||
os.system(f"echo ::set-output name=pull-request-number::{pull_request.number}")
|
|
||||||
# 'pr_number' is deprecated
|
|
||||||
os.system(f"echo ::set-output name=pr_number::{pull_request.number}")
|
|
||||||
|
|
||||||
# Set labels, assignees and milestone
|
|
||||||
if labels is not None:
|
|
||||||
print(f"Applying labels '{labels}'")
|
|
||||||
pull_request.as_issue().edit(labels=cs_string_to_list(labels))
|
|
||||||
if assignees is not None:
|
|
||||||
print(f"Applying assignees '{assignees}'")
|
|
||||||
pull_request.as_issue().edit(assignees=cs_string_to_list(assignees))
|
|
||||||
if milestone is not None:
|
|
||||||
print(f"Applying milestone '{milestone}'")
|
|
||||||
milestone = github_repo.get_milestone(int(milestone))
|
|
||||||
pull_request.as_issue().edit(milestone=milestone)
|
|
||||||
|
|
||||||
# Set pull request reviewers
|
|
||||||
if reviewers is not None:
|
|
||||||
print(f"Requesting reviewers '{reviewers}'")
|
|
||||||
try:
|
|
||||||
pull_request.create_review_request(reviewers=cs_string_to_list(reviewers))
|
|
||||||
except GithubException as e:
|
|
||||||
# Likely caused by "Review cannot be requested from pull request author."
|
|
||||||
if e.status == 422:
|
|
||||||
print("Request reviewers failed - {}".format(e.data["message"]))
|
|
||||||
|
|
||||||
# Set pull request team reviewers
|
|
||||||
if team_reviewers is not None:
|
|
||||||
print(f"Requesting team reviewers '{team_reviewers}'")
|
|
||||||
pull_request.create_review_request(
|
|
||||||
team_reviewers=cs_string_to_list(team_reviewers)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Create a project card for the pull request
|
|
||||||
if project_name is not None and project_column_name is not None:
|
|
||||||
try:
|
|
||||||
create_project_card(
|
|
||||||
github_repo, project_name, project_column_name, pull_request
|
|
||||||
)
|
|
||||||
except GithubException as e:
|
|
||||||
# Likely caused by "Project already has the associated issue."
|
|
||||||
if e.status == 422:
|
|
||||||
print(
|
|
||||||
"Create project card failed - {}".format(
|
|
||||||
e.data["errors"][0]["message"]
|
|
||||||
)
|
|
||||||
)
|
|
229
dist/cpr/create_pull_request.py
vendored
229
dist/cpr/create_pull_request.py
vendored
|
@ -1,229 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
""" Create Pull Request """
|
|
||||||
import base64
|
|
||||||
import common as cmn
|
|
||||||
import create_or_update_branch as coub
|
|
||||||
import create_or_update_pull_request as coupr
|
|
||||||
from git import Repo, GitCommandError
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
# Default the committer and author to the GitHub Actions bot
|
|
||||||
DEFAULT_COMMITTER = "GitHub <noreply@github.com>"
|
|
||||||
DEFAULT_AUTHOR = (
|
|
||||||
"github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"
|
|
||||||
)
|
|
||||||
DEFAULT_COMMIT_MESSAGE = "[create-pull-request] automated change"
|
|
||||||
DEFAULT_TITLE = "Changes by create-pull-request action"
|
|
||||||
DEFAULT_BODY = (
|
|
||||||
"Automated changes by "
|
|
||||||
+ "[create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action"
|
|
||||||
)
|
|
||||||
DEFAULT_BRANCH = "create-pull-request/patch"
|
|
||||||
|
|
||||||
|
|
||||||
def get_git_config_value(repo, name):
|
|
||||||
try:
|
|
||||||
return repo.git.config("--get", name)
|
|
||||||
except GitCommandError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_repository_detail(repo):
|
|
||||||
remote_origin_url = get_git_config_value(repo, "remote.origin.url")
|
|
||||||
if remote_origin_url is None:
|
|
||||||
raise ValueError("Failed to fetch 'remote.origin.url' from git config")
|
|
||||||
protocol, github_repository = cmn.parse_github_repository(remote_origin_url)
|
|
||||||
return remote_origin_url, protocol, github_repository
|
|
||||||
|
|
||||||
|
|
||||||
def git_user_config_is_set(repo):
|
|
||||||
name = get_git_config_value(repo, "user.name")
|
|
||||||
email = get_git_config_value(repo, "user.email")
|
|
||||||
|
|
||||||
if name is not None and email is not None:
|
|
||||||
print(f"Git user already configured as '{name} <{email}>'")
|
|
||||||
return True
|
|
||||||
|
|
||||||
committer_name = get_git_config_value(repo, "committer.name")
|
|
||||||
committer_email = get_git_config_value(repo, "committer.email")
|
|
||||||
author_name = get_git_config_value(repo, "author.name")
|
|
||||||
author_email = get_git_config_value(repo, "author.email")
|
|
||||||
|
|
||||||
if (
|
|
||||||
committer_name is not None
|
|
||||||
and committer_email is not None
|
|
||||||
and author_name is not None
|
|
||||||
and author_email is not None
|
|
||||||
):
|
|
||||||
print(
|
|
||||||
f"Git committer already configured as '{committer_name} <{committer_email}>'"
|
|
||||||
)
|
|
||||||
print(f"Git author already configured as '{author_name} <{author_email}>'")
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def set_committer_author(repo, committer, author):
|
|
||||||
# If either committer or author is supplied they will be cross used
|
|
||||||
if committer is None and author is not None:
|
|
||||||
print("Supplied author will also be used as the committer.")
|
|
||||||
committer = author
|
|
||||||
if author is None and committer is not None:
|
|
||||||
print("Supplied committer will also be used as the author.")
|
|
||||||
author = committer
|
|
||||||
|
|
||||||
# If no committer/author has been supplied but user configuration already
|
|
||||||
# exists in git config we can exit and use the existing config as-is.
|
|
||||||
if committer is None and author is None:
|
|
||||||
if git_user_config_is_set(repo):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Set defaults if no committer/author has been supplied
|
|
||||||
if committer is None and author is None:
|
|
||||||
committer = DEFAULT_COMMITTER
|
|
||||||
author = DEFAULT_AUTHOR
|
|
||||||
|
|
||||||
# Set git environment. This will not persist after the action completes.
|
|
||||||
committer_name, committer_email = cmn.parse_display_name_email(committer)
|
|
||||||
author_name, author_email = cmn.parse_display_name_email(author)
|
|
||||||
repo.git.update_environment(
|
|
||||||
GIT_COMMITTER_NAME=committer_name,
|
|
||||||
GIT_COMMITTER_EMAIL=committer_email,
|
|
||||||
GIT_AUTHOR_NAME=author_name,
|
|
||||||
GIT_AUTHOR_EMAIL=author_email,
|
|
||||||
)
|
|
||||||
print(f"Configured git committer as '{committer_name} <{committer_email}>'")
|
|
||||||
print(f"Configured git author as '{author_name} <{author_email}>'")
|
|
||||||
|
|
||||||
|
|
||||||
# Get required environment variables
|
|
||||||
github_token = os.environ["GITHUB_TOKEN"]
|
|
||||||
# Get environment variables with defaults
|
|
||||||
path = os.getenv("CPR_PATH", os.getcwd())
|
|
||||||
branch = os.getenv("CPR_BRANCH", DEFAULT_BRANCH)
|
|
||||||
commit_message = os.getenv("CPR_COMMIT_MESSAGE", DEFAULT_COMMIT_MESSAGE)
|
|
||||||
# Get environment variables with a default of 'None'
|
|
||||||
committer = os.environ.get("CPR_COMMITTER")
|
|
||||||
author = os.environ.get("CPR_AUTHOR")
|
|
||||||
base = os.environ.get("CPR_BASE")
|
|
||||||
|
|
||||||
# Set the repo path
|
|
||||||
repo = Repo(path)
|
|
||||||
|
|
||||||
# Determine the GitHub repository from git config
|
|
||||||
# This will be the target repository for the pull request
|
|
||||||
repo_url, protocol, github_repository = get_repository_detail(repo)
|
|
||||||
print(f"Target repository set to {github_repository}")
|
|
||||||
|
|
||||||
if protocol == "HTTPS":
|
|
||||||
print(f"::debug::Using HTTPS protocol")
|
|
||||||
# Encode and configure the basic credential for HTTPS access
|
|
||||||
basic_credential = base64.b64encode(
|
|
||||||
f"x-access-token:{github_token}".encode("utf-8")
|
|
||||||
).decode("utf-8")
|
|
||||||
# Mask the basic credential in logs and debug output
|
|
||||||
print(f"::add-mask::{basic_credential}")
|
|
||||||
repo.git.set_persistent_git_options(
|
|
||||||
c=f"http.https://github.com/.extraheader=AUTHORIZATION: basic {basic_credential}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Determine if the checked out ref is a valid base for a pull request
|
|
||||||
# The action needs the checked out HEAD ref to be a branch
|
|
||||||
# This check will fail in the following cases:
|
|
||||||
# - HEAD is detached
|
|
||||||
# - HEAD is a merge commit (pull_request events)
|
|
||||||
# - HEAD is a tag
|
|
||||||
try:
|
|
||||||
working_base = repo.git.symbolic_ref("HEAD", "--short")
|
|
||||||
except GitCommandError as e:
|
|
||||||
print(f"::debug::{e.stderr}")
|
|
||||||
print(
|
|
||||||
f"::error::The checked out ref is not a valid base for a pull request. "
|
|
||||||
+ "Unable to continue. Exiting."
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Exit if the working base is a PR branch created by this action.
|
|
||||||
# This may occur when using a PAT instead of GITHUB_TOKEN because
|
|
||||||
# a PAT allows workflow actions to trigger further events.
|
|
||||||
if working_base.startswith(branch):
|
|
||||||
print(
|
|
||||||
f"::error::Working base branch '{working_base}' was created by this action. "
|
|
||||||
+ "Unable to continue. Exiting."
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Fetch an optional environment variable to determine the branch suffix
|
|
||||||
branch_suffix = os.environ.get("CPR_BRANCH_SUFFIX")
|
|
||||||
if branch_suffix is not None:
|
|
||||||
if branch_suffix == "short-commit-hash":
|
|
||||||
# Suffix with the short SHA1 hash
|
|
||||||
branch = "{}-{}".format(branch, repo.git.rev_parse("--short", "HEAD"))
|
|
||||||
elif branch_suffix == "timestamp":
|
|
||||||
# Suffix with the current timestamp
|
|
||||||
branch = "{}-{}".format(branch, int(time.time()))
|
|
||||||
elif branch_suffix == "random":
|
|
||||||
# Suffix with a 7 character random string
|
|
||||||
branch = "{}-{}".format(branch, cmn.get_random_string())
|
|
||||||
else:
|
|
||||||
print(
|
|
||||||
f"::error::Branch suffix '{branch_suffix}' is not a valid value. "
|
|
||||||
+ "Unable to continue. Exiting."
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Output head branch
|
|
||||||
print(f"Pull request branch to create or update set to '{branch}'")
|
|
||||||
|
|
||||||
# Set the committer and author
|
|
||||||
try:
|
|
||||||
set_committer_author(repo, committer, author)
|
|
||||||
except ValueError as e:
|
|
||||||
print(f"::error::{e} " + "Unable to continue. Exiting.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Create or update the pull request branch
|
|
||||||
result = coub.create_or_update_branch(repo, repo_url, commit_message, base, branch)
|
|
||||||
|
|
||||||
if result["action"] in ["created", "updated"]:
|
|
||||||
# The branch was created or updated
|
|
||||||
print(f"Pushing pull request branch to 'origin/{branch}'")
|
|
||||||
repo.git.push("--force", repo_url, f"HEAD:refs/heads/{branch}")
|
|
||||||
|
|
||||||
# Set the base. It would have been 'None' if not specified as an input
|
|
||||||
base = result["base"]
|
|
||||||
|
|
||||||
# If there is no longer a diff with the base delete the branch and exit
|
|
||||||
if not result["diff"]:
|
|
||||||
print(f"Branch '{branch}' no longer differs from base branch '{base}'")
|
|
||||||
print(f"Closing pull request and deleting branch '{branch}'")
|
|
||||||
repo.git.push("--delete", "--force", repo_url, f"refs/heads/{branch}")
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
# Fetch optional environment variables with default values
|
|
||||||
title = os.getenv("CPR_TITLE", DEFAULT_TITLE)
|
|
||||||
body = os.getenv("CPR_BODY", DEFAULT_BODY)
|
|
||||||
|
|
||||||
# Create or update the pull request
|
|
||||||
coupr.create_or_update_pull_request(
|
|
||||||
github_token,
|
|
||||||
github_repository,
|
|
||||||
branch,
|
|
||||||
base,
|
|
||||||
title,
|
|
||||||
body,
|
|
||||||
os.environ.get("CPR_LABELS"),
|
|
||||||
os.environ.get("CPR_ASSIGNEES"),
|
|
||||||
os.environ.get("CPR_MILESTONE"),
|
|
||||||
os.environ.get("CPR_REVIEWERS"),
|
|
||||||
os.environ.get("CPR_TEAM_REVIEWERS"),
|
|
||||||
os.environ.get("CPR_PROJECT_NAME"),
|
|
||||||
os.environ.get("CPR_PROJECT_COLUMN_NAME"),
|
|
||||||
os.environ.get("CPR_DRAFT"),
|
|
||||||
os.environ.get("CPR_REQUEST_TO_PARENT"),
|
|
||||||
)
|
|
4
dist/cpr/requirements.txt
vendored
4
dist/cpr/requirements.txt
vendored
|
@ -1,4 +0,0 @@
|
||||||
setuptools==46.4.0
|
|
||||||
wheel==0.34.2
|
|
||||||
GitPython==3.1.2
|
|
||||||
PyGithub==1.51
|
|
69
dist/cpr/test_common.py
vendored
69
dist/cpr/test_common.py
vendored
|
@ -1,69 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
""" Test Common """
|
|
||||||
import common as cmn
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_random_string():
|
|
||||||
assert len(cmn.get_random_string()) == 7
|
|
||||||
assert len(cmn.get_random_string(length=20)) == 20
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_github_repository_success():
|
|
||||||
protocol, repository = cmn.parse_github_repository(
|
|
||||||
"https://github.com/peter-evans/create-pull-request"
|
|
||||||
)
|
|
||||||
assert protocol == "HTTPS"
|
|
||||||
assert repository == "peter-evans/create-pull-request"
|
|
||||||
|
|
||||||
protocol, repository = cmn.parse_github_repository(
|
|
||||||
"https://xxx:x-oauth-basic@github.com/peter-evans/create-pull-request"
|
|
||||||
)
|
|
||||||
assert protocol == "HTTPS"
|
|
||||||
assert repository == "peter-evans/create-pull-request"
|
|
||||||
|
|
||||||
protocol, repository = cmn.parse_github_repository(
|
|
||||||
"git@github.com:peter-evans/create-pull-request.git"
|
|
||||||
)
|
|
||||||
assert protocol == "SSH"
|
|
||||||
assert repository == "peter-evans/create-pull-request"
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_github_repository_failure():
|
|
||||||
url = "https://github.com/peter-evans"
|
|
||||||
with pytest.raises(ValueError) as e_info:
|
|
||||||
cmn.parse_github_repository(url)
|
|
||||||
assert (
|
|
||||||
e_info.value.args[0]
|
|
||||||
== f"The format of '{url}' is not a valid GitHub repository URL"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_display_name_email_success():
|
|
||||||
name, email = cmn.parse_display_name_email("abc def <abc@def.com>")
|
|
||||||
assert name == "abc def"
|
|
||||||
assert email == "abc@def.com"
|
|
||||||
|
|
||||||
name, email = cmn.parse_display_name_email(
|
|
||||||
"github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"
|
|
||||||
)
|
|
||||||
assert name == "github-actions[bot]"
|
|
||||||
assert email == "41898282+github-actions[bot]@users.noreply.github.com"
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_display_name_email_failure():
|
|
||||||
display_name_email = "abc@def.com"
|
|
||||||
with pytest.raises(ValueError) as e_info:
|
|
||||||
cmn.parse_display_name_email(display_name_email)
|
|
||||||
assert (
|
|
||||||
e_info.value.args[0]
|
|
||||||
== f"The format of '{display_name_email}' is not a valid email address with display name"
|
|
||||||
)
|
|
||||||
|
|
||||||
display_name_email = " < >"
|
|
||||||
with pytest.raises(ValueError) as e_info:
|
|
||||||
cmn.parse_display_name_email(display_name_email)
|
|
||||||
assert (
|
|
||||||
e_info.value.args[0]
|
|
||||||
== f"The format of '{display_name_email}' is not a valid email address with display name"
|
|
||||||
)
|
|
757
dist/cpr/test_create_or_update_branch.py
vendored
757
dist/cpr/test_create_or_update_branch.py
vendored
|
@ -1,757 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
""" Test Create or Update Branch """
|
|
||||||
import create_or_update_branch as coub
|
|
||||||
from git import Repo
|
|
||||||
import os
|
|
||||||
import pytest
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
# Set git repo
|
|
||||||
REPO_PATH = os.getenv("COUB_REPO_PATH", os.getcwd())
|
|
||||||
repo = Repo(REPO_PATH)
|
|
||||||
|
|
||||||
# Set git environment
|
|
||||||
author_name = "github-actions[bot]"
|
|
||||||
author_email = "41898282+github-actions[bot]@users.noreply.github.com"
|
|
||||||
committer_name = "GitHub"
|
|
||||||
committer_email = "noreply@github.com"
|
|
||||||
repo.git.update_environment(
|
|
||||||
GIT_AUTHOR_NAME=author_name,
|
|
||||||
GIT_AUTHOR_EMAIL=author_email,
|
|
||||||
GIT_COMMITTER_NAME=committer_name,
|
|
||||||
GIT_COMMITTER_EMAIL=committer_email,
|
|
||||||
)
|
|
||||||
|
|
||||||
REPO_URL = repo.git.config("--get", "remote.origin.url")
|
|
||||||
|
|
||||||
TRACKED_FILE = "tracked-file.txt"
|
|
||||||
UNTRACKED_FILE = "untracked-file.txt"
|
|
||||||
|
|
||||||
DEFAULT_BRANCH = "tests/master"
|
|
||||||
NOT_BASE_BRANCH = "tests/branch-that-is-not-the-base"
|
|
||||||
NOT_EXIST_BRANCH = "tests/branch-that-does-not-exist"
|
|
||||||
|
|
||||||
COMMIT_MESSAGE = "[create-pull-request] automated change"
|
|
||||||
BRANCH = "tests/create-pull-request/patch"
|
|
||||||
BASE = DEFAULT_BRANCH
|
|
||||||
|
|
||||||
|
|
||||||
def create_tracked_change(content=None):
|
|
||||||
if content is None:
|
|
||||||
content = str(time.time())
|
|
||||||
# Create a tracked file change
|
|
||||||
with open(os.path.join(REPO_PATH, TRACKED_FILE), "w") as f:
|
|
||||||
f.write(content)
|
|
||||||
return content
|
|
||||||
|
|
||||||
|
|
||||||
def create_untracked_change(content=None):
|
|
||||||
if content is None:
|
|
||||||
content = str(time.time())
|
|
||||||
# Create an untracked file change
|
|
||||||
with open(os.path.join(REPO_PATH, UNTRACKED_FILE), "w") as f:
|
|
||||||
f.write(content)
|
|
||||||
return content
|
|
||||||
|
|
||||||
|
|
||||||
def get_tracked_content():
|
|
||||||
# Read the content of the tracked file
|
|
||||||
with open(os.path.join(REPO_PATH, TRACKED_FILE), "r") as f:
|
|
||||||
return f.read()
|
|
||||||
|
|
||||||
|
|
||||||
def get_untracked_content():
|
|
||||||
# Read the content of the untracked file
|
|
||||||
with open(os.path.join(REPO_PATH, UNTRACKED_FILE), "r") as f:
|
|
||||||
return f.read()
|
|
||||||
|
|
||||||
|
|
||||||
def create_changes(tracked_content=None, untracked_content=None):
|
|
||||||
tracked_content = create_tracked_change(tracked_content)
|
|
||||||
untracked_content = create_untracked_change(untracked_content)
|
|
||||||
return tracked_content, untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
def create_commits(number=2, final_tracked_content=None, final_untracked_content=None):
|
|
||||||
for i in range(number):
|
|
||||||
commit_number = i + 1
|
|
||||||
if commit_number == number:
|
|
||||||
tracked_content, untracked_content = create_changes(
|
|
||||||
final_tracked_content, final_untracked_content
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
repo.git.add("-A")
|
|
||||||
repo.git.commit(m=f"Commit {commit_number}")
|
|
||||||
return tracked_content, untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module", autouse=True)
|
|
||||||
def before_after_all():
|
|
||||||
print("Before all tests")
|
|
||||||
# Check there are no local changes that might be
|
|
||||||
# destroyed by running these tests
|
|
||||||
assert not repo.is_dirty(untracked_files=True)
|
|
||||||
|
|
||||||
# Create a new default branch for the test run
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
repo.git.checkout("master")
|
|
||||||
repo.git.checkout("HEAD", b=NOT_BASE_BRANCH)
|
|
||||||
create_tracked_change()
|
|
||||||
repo.git.add("-A")
|
|
||||||
repo.git.commit(m="This commit should not appear in pr branches")
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{NOT_BASE_BRANCH}")
|
|
||||||
# Create a new default branch for the test run
|
|
||||||
repo.git.checkout("master")
|
|
||||||
repo.git.checkout("HEAD", b=DEFAULT_BRANCH)
|
|
||||||
create_tracked_change()
|
|
||||||
repo.git.add("-A")
|
|
||||||
repo.git.commit(m="Add file to be a tracked file for tests")
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
|
|
||||||
yield
|
|
||||||
|
|
||||||
print("After all tests")
|
|
||||||
repo.git.checkout("master")
|
|
||||||
# Delete the "not base branch" created for the test run
|
|
||||||
repo.git.branch("--delete", "--force", NOT_BASE_BRANCH)
|
|
||||||
repo.git.push("--delete", "--force", REPO_URL, f"refs/heads/{NOT_BASE_BRANCH}")
|
|
||||||
# Delete the default branch created for the test run
|
|
||||||
repo.git.branch("--delete", "--force", DEFAULT_BRANCH)
|
|
||||||
repo.git.push("--delete", "--force", REPO_URL, f"refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
|
|
||||||
|
|
||||||
def before_test():
|
|
||||||
print("Before test")
|
|
||||||
# Checkout the default branch
|
|
||||||
repo.git.checkout(DEFAULT_BRANCH)
|
|
||||||
|
|
||||||
|
|
||||||
def after_test(delete_remote=True):
|
|
||||||
print("After test")
|
|
||||||
# Output git log
|
|
||||||
print(repo.git.log("-5", pretty="oneline"))
|
|
||||||
# Delete the pull request branch if it exists
|
|
||||||
repo.git.checkout(DEFAULT_BRANCH)
|
|
||||||
print(f"Deleting {BRANCH}")
|
|
||||||
for branch in repo.branches:
|
|
||||||
if branch.name == BRANCH:
|
|
||||||
repo.git.branch("--delete", "--force", BRANCH)
|
|
||||||
break
|
|
||||||
if delete_remote:
|
|
||||||
print(f"Deleting origin/{BRANCH}")
|
|
||||||
for ref in repo.remotes.origin.refs:
|
|
||||||
if ref.name == f"origin/{BRANCH}":
|
|
||||||
repo.git.push("--delete", "--force", REPO_URL, f"refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch("--prune")
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
|
||||||
def before_after_tests():
|
|
||||||
before_test()
|
|
||||||
yield
|
|
||||||
after_test()
|
|
||||||
|
|
||||||
|
|
||||||
# Tests if a branch exists and can be fetched
|
|
||||||
def coub_fetch_successful():
|
|
||||||
assert coub.fetch_successful(repo, REPO_URL, NOT_BASE_BRANCH)
|
|
||||||
assert not coub.fetch_successful(repo, REPO_URL, NOT_EXIST_BRANCH)
|
|
||||||
|
|
||||||
|
|
||||||
# Tests no changes resulting in no new branch being created
|
|
||||||
def coub_no_changes_on_create():
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "none"
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with a tracked file change
|
|
||||||
def coub_tracked_changes():
|
|
||||||
# Create a tracked file change
|
|
||||||
tracked_content = create_tracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create a tracked file change
|
|
||||||
tracked_content = create_tracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with an untracked file change
|
|
||||||
def coub_untracked_changes():
|
|
||||||
# Create an untracked file change
|
|
||||||
untracked_content = create_untracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create an untracked file change
|
|
||||||
untracked_content = create_untracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with identical changes
|
|
||||||
# The pull request branch will not be updated
|
|
||||||
def coub_identical_changes():
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create identical tracked and untracked file changes
|
|
||||||
create_changes(tracked_content, untracked_content)
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "none"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with commits on the base inbetween
|
|
||||||
def coub_commits_on_base():
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the base
|
|
||||||
create_commits()
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and then an update with no changes
|
|
||||||
# This effectively reverts the branch back to match the base and results in no diff
|
|
||||||
def coub_changes_no_diff():
|
|
||||||
# Save the default branch tracked content
|
|
||||||
default_tracked_content = get_tracked_content()
|
|
||||||
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Running with no update effectively reverts the branch back to match the base
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"] == False
|
|
||||||
assert get_tracked_content() == default_tracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with commits on the base inbetween
|
|
||||||
# The changes on base effectively revert the branch back to match the base and results in no diff
|
|
||||||
def coub_commits_on_base_no_diff():
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the base
|
|
||||||
tracked_content, untracked_content = create_commits()
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
# Create the same tracked and untracked file changes that were made to the base
|
|
||||||
create_changes(tracked_content, untracked_content)
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"] == False
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with commits on the working base (during the workflow)
|
|
||||||
def coub_commits_on_working_base():
|
|
||||||
# Create commits on the working base
|
|
||||||
tracked_content, untracked_content = create_commits()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the working base
|
|
||||||
tracked_content, untracked_content = create_commits()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with changes and commits on the working base (during the workflow)
|
|
||||||
def coub_changes_and_commits_on_working_base():
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with changes and commits on the working base (during the workflow)
|
|
||||||
# with commits on the base inbetween
|
|
||||||
def coub_changes_and_commits_on_base_and_working_base():
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the base
|
|
||||||
create_commits()
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests no changes resulting in no new branch being created
|
|
||||||
def coub_wbnb_no_changes_on_create():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "none"
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with a tracked file change
|
|
||||||
def coub_wbnb_tracked_changes():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create a tracked file change
|
|
||||||
tracked_content = create_tracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create a tracked file change
|
|
||||||
tracked_content = create_tracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with an untracked file change
|
|
||||||
def coub_wbnb_untracked_changes():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create an untracked file change
|
|
||||||
untracked_content = create_untracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create an untracked file change
|
|
||||||
untracked_content = create_untracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with identical changes
|
|
||||||
# The pull request branch will not be updated
|
|
||||||
def coub_wbnb_identical_changes():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create identical tracked and untracked file changes
|
|
||||||
create_changes(tracked_content, untracked_content)
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "none"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with commits on the base inbetween
|
|
||||||
def coub_wbnb_commits_on_base():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the base
|
|
||||||
create_commits()
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and then an update with no changes
|
|
||||||
# This effectively reverts the branch back to match the base and results in no diff
|
|
||||||
def coub_wbnb_changes_no_diff():
|
|
||||||
# Save the default branch tracked content
|
|
||||||
default_tracked_content = get_tracked_content()
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Running with no update effectively reverts the branch back to match the base
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"] == False
|
|
||||||
assert get_tracked_content() == default_tracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with commits on the base inbetween
|
|
||||||
# The changes on base effectively revert the branch back to match the base and results in no diff
|
|
||||||
# This scenario will cause cherrypick to fail due to an empty commit.
|
|
||||||
# The commit is empty because the changes now exist on the base.
|
|
||||||
def coub_wbnb_commits_on_base_no_diff():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the base
|
|
||||||
tracked_content, untracked_content = create_commits()
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create the same tracked and untracked file changes that were made to the base
|
|
||||||
create_changes(tracked_content, untracked_content)
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"] == False
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with commits on the working base (during the workflow)
|
|
||||||
def coub_wbnb_commits_on_working_base():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create commits on the working base
|
|
||||||
tracked_content, untracked_content = create_commits()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create commits on the working base
|
|
||||||
tracked_content, untracked_content = create_commits()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with changes and commits on the working base (during the workflow)
|
|
||||||
def coub_wbnb_changes_and_commits_on_working_base():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with changes and commits on the working base (during the workflow)
|
|
||||||
# with commits on the base inbetween
|
|
||||||
def coub_wbnb_changes_and_commits_on_base_and_working_base():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the base
|
|
||||||
create_commits()
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# pytest -v -s ~/git/create-pull-request/src
|
|
||||||
|
|
||||||
test_coub_fetch_successful = coub_fetch_successful
|
|
||||||
|
|
||||||
test_coub_no_changes_on_create = coub_no_changes_on_create
|
|
||||||
test_coub_tracked_changes = coub_tracked_changes
|
|
||||||
test_coub_untracked_changes = coub_untracked_changes
|
|
||||||
test_coub_identical_changes = coub_identical_changes
|
|
||||||
test_coub_commits_on_base = coub_commits_on_base
|
|
||||||
|
|
||||||
test_coub_changes_no_diff = coub_changes_no_diff
|
|
||||||
test_coub_commits_on_base_no_diff = coub_commits_on_base_no_diff
|
|
||||||
|
|
||||||
test_coub_commits_on_working_base = coub_commits_on_working_base
|
|
||||||
test_coub_changes_and_commits_on_working_base = coub_changes_and_commits_on_working_base
|
|
||||||
test_coub_changes_and_commits_on_base_and_working_base = (
|
|
||||||
coub_changes_and_commits_on_base_and_working_base
|
|
||||||
)
|
|
||||||
|
|
||||||
# WBNB
|
|
||||||
test_coub_wbnb_no_changes_on_create = coub_wbnb_no_changes_on_create
|
|
||||||
test_coub_wbnb_tracked_changes = coub_wbnb_tracked_changes
|
|
||||||
test_coub_wbnb_untracked_changes = coub_wbnb_untracked_changes
|
|
||||||
test_coub_wbnb_identical_changes = coub_wbnb_identical_changes
|
|
||||||
test_coub_wbnb_commits_on_base = coub_wbnb_commits_on_base
|
|
||||||
|
|
||||||
test_coub_wbnb_changes_no_diff = coub_wbnb_changes_no_diff
|
|
||||||
test_coub_wbnb_commits_on_base_no_diff = coub_wbnb_commits_on_base_no_diff
|
|
||||||
|
|
||||||
test_coub_wbnb_commits_on_working_base = coub_wbnb_commits_on_working_base
|
|
||||||
test_coub_wbnb_changes_and_commits_on_working_base = (
|
|
||||||
coub_wbnb_changes_and_commits_on_working_base
|
|
||||||
)
|
|
||||||
test_coub_wbnb_changes_and_commits_on_base_and_working_base = (
|
|
||||||
coub_wbnb_changes_and_commits_on_base_and_working_base
|
|
||||||
)
|
|
BIN
dist/vendor/Deprecated-1.2.10.tar.gz
vendored
BIN
dist/vendor/Deprecated-1.2.10.tar.gz
vendored
Binary file not shown.
BIN
dist/vendor/GitPython-3.1.2.tar.gz
vendored
BIN
dist/vendor/GitPython-3.1.2.tar.gz
vendored
Binary file not shown.
BIN
dist/vendor/PyGithub-1.51.tar.gz
vendored
BIN
dist/vendor/PyGithub-1.51.tar.gz
vendored
Binary file not shown.
BIN
dist/vendor/PyJWT-1.7.1.tar.gz
vendored
BIN
dist/vendor/PyJWT-1.7.1.tar.gz
vendored
Binary file not shown.
BIN
dist/vendor/certifi-2020.6.20.tar.gz
vendored
BIN
dist/vendor/certifi-2020.6.20.tar.gz
vendored
Binary file not shown.
BIN
dist/vendor/chardet-3.0.4.tar.gz
vendored
BIN
dist/vendor/chardet-3.0.4.tar.gz
vendored
Binary file not shown.
BIN
dist/vendor/gitdb-4.0.5.tar.gz
vendored
BIN
dist/vendor/gitdb-4.0.5.tar.gz
vendored
Binary file not shown.
BIN
dist/vendor/idna-2.9.tar.gz
vendored
BIN
dist/vendor/idna-2.9.tar.gz
vendored
Binary file not shown.
BIN
dist/vendor/requests-2.24.0.tar.gz
vendored
BIN
dist/vendor/requests-2.24.0.tar.gz
vendored
Binary file not shown.
BIN
dist/vendor/setuptools-46.4.0.zip
vendored
BIN
dist/vendor/setuptools-46.4.0.zip
vendored
Binary file not shown.
BIN
dist/vendor/smmap-3.0.4.tar.gz
vendored
BIN
dist/vendor/smmap-3.0.4.tar.gz
vendored
Binary file not shown.
BIN
dist/vendor/urllib3-1.25.9.tar.gz
vendored
BIN
dist/vendor/urllib3-1.25.9.tar.gz
vendored
Binary file not shown.
BIN
dist/vendor/wheel-0.34.2.tar.gz
vendored
BIN
dist/vendor/wheel-0.34.2.tar.gz
vendored
Binary file not shown.
BIN
dist/vendor/wrapt-1.12.1.tar.gz
vendored
BIN
dist/vendor/wrapt-1.12.1.tar.gz
vendored
Binary file not shown.
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "create-pull-request",
|
"name": "create-pull-request",
|
||||||
"version": "2.0.0",
|
"version": "3.0.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -4011,7 +4011,9 @@
|
||||||
"is-docker": {
|
"is-docker": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.0.0.tgz",
|
||||||
"integrity": "sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ=="
|
"integrity": "sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"is-extendable": {
|
"is-extendable": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
|
|
11
package.json
11
package.json
|
@ -1,11 +1,11 @@
|
||||||
{
|
{
|
||||||
"name": "create-pull-request",
|
"name": "create-pull-request",
|
||||||
"version": "2.0.0",
|
"version": "3.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Creates a pull request for changes to your repository in the actions workspace",
|
"description": "Creates a pull request for changes to your repository in the actions workspace",
|
||||||
"main": "lib/main.js",
|
"main": "lib/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rm -rf dist",
|
"clean": "echo Temporarily kept for backwards compatibility",
|
||||||
"build": "tsc && ncc build",
|
"build": "tsc && ncc build",
|
||||||
"format": "prettier --write '**/*.ts'",
|
"format": "prettier --write '**/*.ts'",
|
||||||
"format-check": "prettier --check '**/*.ts'",
|
"format-check": "prettier --check '**/*.ts'",
|
||||||
|
@ -13,9 +13,9 @@
|
||||||
"test:unit": "jest unit",
|
"test:unit": "jest unit",
|
||||||
"test:int": "__test__/integration-tests.sh",
|
"test:int": "__test__/integration-tests.sh",
|
||||||
"test": "npm run test:unit && npm run test:int",
|
"test": "npm run test:unit && npm run test:int",
|
||||||
"pack-assets": "mkdir -p dist/cpr && cp -rv src/cpr/* dist/cpr",
|
"pack-assets": "echo Temporarily kept for backwards compatibility",
|
||||||
"vendor-deps": "pip download -r src/cpr/requirements.txt --no-binary=:all: -d dist/vendor",
|
"vendor-deps": "echo Temporarily kept for backwards compatibility",
|
||||||
"package": "npm run build && npm run pack-assets && npm run vendor-deps"
|
"package": "echo Temporarily kept for backwards compatibility"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -39,7 +39,6 @@
|
||||||
"@octokit/core": "3.1.0",
|
"@octokit/core": "3.1.0",
|
||||||
"@octokit/plugin-paginate-rest": "2.2.3",
|
"@octokit/plugin-paginate-rest": "2.2.3",
|
||||||
"@octokit/plugin-rest-endpoint-methods": "4.0.0",
|
"@octokit/plugin-rest-endpoint-methods": "4.0.0",
|
||||||
"is-docker": "2.0.0",
|
|
||||||
"uuid": "8.2.0"
|
"uuid": "8.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"extends": [
|
|
||||||
"config:base"
|
|
||||||
],
|
|
||||||
"enabledManagers": ["pip_requirements"],
|
|
||||||
"ignorePaths": [
|
|
||||||
"**/dist/**"
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
import random
|
|
||||||
import re
|
|
||||||
import string
|
|
||||||
|
|
||||||
|
|
||||||
def get_random_string(length=7, chars=string.ascii_lowercase + string.digits):
|
|
||||||
return "".join(random.choice(chars) for _ in range(length))
|
|
||||||
|
|
||||||
|
|
||||||
def parse_github_repository(url):
|
|
||||||
# Parse the protocol and github repository from a URL
|
|
||||||
# e.g. HTTPS, peter-evans/create-pull-request
|
|
||||||
https_pattern = re.compile(r"^https://.*@?github.com/(.+/.+)$")
|
|
||||||
ssh_pattern = re.compile(r"^git@github.com:(.+/.+).git$")
|
|
||||||
|
|
||||||
match = https_pattern.match(url)
|
|
||||||
if match is not None:
|
|
||||||
return "HTTPS", match.group(1)
|
|
||||||
|
|
||||||
match = ssh_pattern.match(url)
|
|
||||||
if match is not None:
|
|
||||||
return "SSH", match.group(1)
|
|
||||||
|
|
||||||
raise ValueError(f"The format of '{url}' is not a valid GitHub repository URL")
|
|
||||||
|
|
||||||
|
|
||||||
def parse_display_name_email(display_name_email):
|
|
||||||
# Parse the name and email address from a string in the following format
|
|
||||||
# Display Name <email@address.com>
|
|
||||||
pattern = re.compile(r"^([^<]+)\s*<([^>]+)>$")
|
|
||||||
|
|
||||||
# Check we have a match
|
|
||||||
match = pattern.match(display_name_email)
|
|
||||||
if match is None:
|
|
||||||
raise ValueError(
|
|
||||||
f"The format of '{display_name_email}' is not a valid email address with display name"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check that name and email are not just whitespace
|
|
||||||
name = match.group(1).strip()
|
|
||||||
email = match.group(2).strip()
|
|
||||||
if len(name) == 0 or len(email) == 0:
|
|
||||||
raise ValueError(
|
|
||||||
f"The format of '{display_name_email}' is not a valid email address with display name"
|
|
||||||
)
|
|
||||||
|
|
||||||
return name, email
|
|
|
@ -1,145 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
""" Create or Update Branch """
|
|
||||||
import common as cmn
|
|
||||||
from git import Repo, GitCommandError
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
CHERRYPICK_EMPTY = (
|
|
||||||
"The previous cherry-pick is now empty, possibly due to conflict resolution."
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_successful(repo, repo_url, branch):
|
|
||||||
try:
|
|
||||||
repo.git.fetch(repo_url, f"{branch}:refs/remotes/origin/{branch}")
|
|
||||||
except GitCommandError:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def is_ahead(repo, branch_1, branch_2):
|
|
||||||
# Return true if branch_2 is ahead of branch_1
|
|
||||||
return (
|
|
||||||
int(repo.git.rev_list("--right-only", "--count", f"{branch_1}...{branch_2}"))
|
|
||||||
> 0
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def is_behind(repo, branch_1, branch_2):
|
|
||||||
# Return true if branch_2 is behind branch_1
|
|
||||||
return (
|
|
||||||
int(repo.git.rev_list("--left-only", "--count", f"{branch_1}...{branch_2}")) > 0
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def is_even(repo, branch_1, branch_2):
|
|
||||||
# Return true if branch_2 is even with branch_1
|
|
||||||
return not is_ahead(repo, branch_1, branch_2) and not is_behind(
|
|
||||||
repo, branch_1, branch_2
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def has_diff(repo, branch_1, branch_2):
|
|
||||||
diff = repo.git.diff(f"{branch_1}..{branch_2}")
|
|
||||||
return len(diff) > 0
|
|
||||||
|
|
||||||
|
|
||||||
def create_or_update_branch(repo, repo_url, commit_message, base, branch):
|
|
||||||
# Set the default return values
|
|
||||||
action = "none"
|
|
||||||
diff = False
|
|
||||||
|
|
||||||
# Get the working base. This may or may not be the actual base.
|
|
||||||
working_base = repo.git.symbolic_ref("HEAD", "--short")
|
|
||||||
# If the base is not specified it is assumed to be the working base
|
|
||||||
if base is None:
|
|
||||||
base = working_base
|
|
||||||
|
|
||||||
# Save the working base changes to a temporary branch
|
|
||||||
temp_branch = cmn.get_random_string(length=20)
|
|
||||||
repo.git.checkout("HEAD", b=temp_branch)
|
|
||||||
# Commit any uncomitted changes
|
|
||||||
if repo.is_dirty(untracked_files=True):
|
|
||||||
print(f"Uncommitted changes found. Adding a commit.")
|
|
||||||
repo.git.add("-A")
|
|
||||||
repo.git.commit(m=commit_message)
|
|
||||||
|
|
||||||
# Perform fetch and reset the working base
|
|
||||||
# Commits made during the workflow will be removed
|
|
||||||
repo.git.fetch("--force", repo_url, f"{working_base}:{working_base}")
|
|
||||||
|
|
||||||
# If the working base is not the base, rebase the temp branch commits
|
|
||||||
if working_base != base:
|
|
||||||
print(
|
|
||||||
f"Rebasing commits made to branch '{working_base}' on to base branch '{base}'"
|
|
||||||
)
|
|
||||||
# Checkout the actual base
|
|
||||||
repo.git.fetch("--force", repo_url, f"{base}:{base}")
|
|
||||||
repo.git.checkout(base)
|
|
||||||
# Cherrypick commits from the temporary branch starting from the working base
|
|
||||||
commits = repo.git.rev_list("--reverse", f"{working_base}..{temp_branch}", ".")
|
|
||||||
for commit in commits.splitlines():
|
|
||||||
try:
|
|
||||||
repo.git.cherry_pick(
|
|
||||||
"--strategy",
|
|
||||||
"recursive",
|
|
||||||
"--strategy-option",
|
|
||||||
"theirs",
|
|
||||||
f"{commit}",
|
|
||||||
)
|
|
||||||
except GitCommandError as e:
|
|
||||||
if CHERRYPICK_EMPTY not in e.stderr:
|
|
||||||
print("Unexpected error: ", e)
|
|
||||||
raise
|
|
||||||
# Reset the temp branch to the working index
|
|
||||||
repo.git.checkout("-B", temp_branch, "HEAD")
|
|
||||||
# Reset the base
|
|
||||||
repo.git.fetch("--force", repo_url, f"{base}:{base}")
|
|
||||||
|
|
||||||
# Try to fetch the pull request branch
|
|
||||||
if not fetch_successful(repo, repo_url, branch):
|
|
||||||
# The pull request branch does not exist
|
|
||||||
print(f"Pull request branch '{branch}' does not exist yet")
|
|
||||||
# Create the pull request branch
|
|
||||||
repo.git.checkout("HEAD", b=branch)
|
|
||||||
# Check if the pull request branch is ahead of the base
|
|
||||||
diff = is_ahead(repo, base, branch)
|
|
||||||
if diff:
|
|
||||||
action = "created"
|
|
||||||
print(f"Created branch '{branch}'")
|
|
||||||
else:
|
|
||||||
print(
|
|
||||||
f"Branch '{branch}' is not ahead of base '{base}' and will not be created"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# The pull request branch exists
|
|
||||||
print(
|
|
||||||
f"Pull request branch '{branch}' already exists as remote branch 'origin/{branch}'"
|
|
||||||
)
|
|
||||||
# Checkout the pull request branch
|
|
||||||
repo.git.checkout(branch)
|
|
||||||
|
|
||||||
if has_diff(repo, branch, temp_branch):
|
|
||||||
# If the branch differs from the recreated temp version then the branch is reset
|
|
||||||
# For changes on base this action is similar to a rebase of the pull request branch
|
|
||||||
print(f"Resetting '{branch}'")
|
|
||||||
repo.git.checkout("-B", branch, temp_branch)
|
|
||||||
# repo.git.switch("-C", branch, temp_branch)
|
|
||||||
|
|
||||||
# Check if the pull request branch has been updated
|
|
||||||
# If the branch was reset or updated it will be ahead
|
|
||||||
# It may be behind if a reset now results in no diff with the base
|
|
||||||
if not is_even(repo, f"origin/{branch}", branch):
|
|
||||||
action = "updated"
|
|
||||||
print(f"Updated branch '{branch}'")
|
|
||||||
else:
|
|
||||||
print(f"Branch '{branch}' is even with its remote and will not be updated")
|
|
||||||
|
|
||||||
# Check if the pull request branch is ahead of the base
|
|
||||||
diff = is_ahead(repo, base, branch)
|
|
||||||
|
|
||||||
# Delete the temporary branch
|
|
||||||
repo.git.branch("--delete", "--force", temp_branch)
|
|
||||||
|
|
||||||
return {"action": action, "diff": diff, "base": base}
|
|
|
@ -1,162 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
""" Create or Update Pull Request """
|
|
||||||
from github import Github, GithubException
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
def string_to_bool(str):
|
|
||||||
if str is None:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return str.lower() in [
|
|
||||||
"true",
|
|
||||||
"1",
|
|
||||||
"t",
|
|
||||||
"y",
|
|
||||||
"yes",
|
|
||||||
"on",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def cs_string_to_list(str):
|
|
||||||
# Split the comma separated string into a list
|
|
||||||
l = [i.strip() for i in str.split(",")]
|
|
||||||
# Remove empty strings
|
|
||||||
return list(filter(None, l))
|
|
||||||
|
|
||||||
|
|
||||||
def create_project_card(github_repo, project_name, project_column_name, pull_request):
|
|
||||||
# Locate the project by name
|
|
||||||
project = None
|
|
||||||
for project_item in github_repo.get_projects("all"):
|
|
||||||
if project_item.name == project_name:
|
|
||||||
project = project_item
|
|
||||||
break
|
|
||||||
|
|
||||||
if not project:
|
|
||||||
print("::error::Project not found. Unable to create project card.")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Locate the column by name
|
|
||||||
column = None
|
|
||||||
for column_item in project.get_columns():
|
|
||||||
if column_item.name == project_column_name:
|
|
||||||
column = column_item
|
|
||||||
break
|
|
||||||
|
|
||||||
if not column:
|
|
||||||
print("::error::Project column not found. Unable to create project card.")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Create a project card for the pull request
|
|
||||||
column.create_card(content_id=pull_request.id, content_type="PullRequest")
|
|
||||||
print(
|
|
||||||
"Added pull request #%d to project '%s' under column '%s'"
|
|
||||||
% (pull_request.number, project.name, column.name)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def create_or_update_pull_request(
|
|
||||||
github_token,
|
|
||||||
github_repository,
|
|
||||||
branch,
|
|
||||||
base,
|
|
||||||
title,
|
|
||||||
body,
|
|
||||||
labels,
|
|
||||||
assignees,
|
|
||||||
milestone,
|
|
||||||
reviewers,
|
|
||||||
team_reviewers,
|
|
||||||
project_name,
|
|
||||||
project_column_name,
|
|
||||||
draft,
|
|
||||||
request_to_parent,
|
|
||||||
):
|
|
||||||
github_repo = head_repo = Github(github_token).get_repo(github_repository)
|
|
||||||
if string_to_bool(request_to_parent):
|
|
||||||
github_repo = github_repo.parent
|
|
||||||
if github_repo is None:
|
|
||||||
raise ValueError(
|
|
||||||
"The checked out repository is not a fork. Input 'request-to-parent' should be set to false."
|
|
||||||
)
|
|
||||||
|
|
||||||
head_branch = f"{head_repo.owner.login}:{branch}"
|
|
||||||
|
|
||||||
# Create the pull request
|
|
||||||
try:
|
|
||||||
pull_request = github_repo.create_pull(
|
|
||||||
title=title,
|
|
||||||
body=body,
|
|
||||||
base=base,
|
|
||||||
head=head_branch,
|
|
||||||
draft=string_to_bool(draft),
|
|
||||||
)
|
|
||||||
print(
|
|
||||||
f"Created pull request #{pull_request.number} ({head_branch} => {github_repo.owner.login}:{base})"
|
|
||||||
)
|
|
||||||
except GithubException as e:
|
|
||||||
if e.status == 422:
|
|
||||||
# A pull request exists for this branch and base
|
|
||||||
# Get the pull request
|
|
||||||
pull_request = github_repo.get_pulls(
|
|
||||||
state="open", base=base, head=head_branch
|
|
||||||
)[0]
|
|
||||||
# Update title and body
|
|
||||||
pull_request.as_issue().edit(title=title, body=body)
|
|
||||||
print(
|
|
||||||
f"Updated pull request #{pull_request.number} ({head_branch} => {github_repo.owner.login}:{base})"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
print(str(e))
|
|
||||||
raise
|
|
||||||
|
|
||||||
# Set the output variables
|
|
||||||
os.system(f"echo ::set-env name=PULL_REQUEST_NUMBER::{pull_request.number}")
|
|
||||||
os.system(f"echo ::set-output name=pull-request-number::{pull_request.number}")
|
|
||||||
# 'pr_number' is deprecated
|
|
||||||
os.system(f"echo ::set-output name=pr_number::{pull_request.number}")
|
|
||||||
|
|
||||||
# Set labels, assignees and milestone
|
|
||||||
if labels is not None:
|
|
||||||
print(f"Applying labels '{labels}'")
|
|
||||||
pull_request.as_issue().edit(labels=cs_string_to_list(labels))
|
|
||||||
if assignees is not None:
|
|
||||||
print(f"Applying assignees '{assignees}'")
|
|
||||||
pull_request.as_issue().edit(assignees=cs_string_to_list(assignees))
|
|
||||||
if milestone is not None:
|
|
||||||
print(f"Applying milestone '{milestone}'")
|
|
||||||
milestone = github_repo.get_milestone(int(milestone))
|
|
||||||
pull_request.as_issue().edit(milestone=milestone)
|
|
||||||
|
|
||||||
# Set pull request reviewers
|
|
||||||
if reviewers is not None:
|
|
||||||
print(f"Requesting reviewers '{reviewers}'")
|
|
||||||
try:
|
|
||||||
pull_request.create_review_request(reviewers=cs_string_to_list(reviewers))
|
|
||||||
except GithubException as e:
|
|
||||||
# Likely caused by "Review cannot be requested from pull request author."
|
|
||||||
if e.status == 422:
|
|
||||||
print("Request reviewers failed - {}".format(e.data["message"]))
|
|
||||||
|
|
||||||
# Set pull request team reviewers
|
|
||||||
if team_reviewers is not None:
|
|
||||||
print(f"Requesting team reviewers '{team_reviewers}'")
|
|
||||||
pull_request.create_review_request(
|
|
||||||
team_reviewers=cs_string_to_list(team_reviewers)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Create a project card for the pull request
|
|
||||||
if project_name is not None and project_column_name is not None:
|
|
||||||
try:
|
|
||||||
create_project_card(
|
|
||||||
github_repo, project_name, project_column_name, pull_request
|
|
||||||
)
|
|
||||||
except GithubException as e:
|
|
||||||
# Likely caused by "Project already has the associated issue."
|
|
||||||
if e.status == 422:
|
|
||||||
print(
|
|
||||||
"Create project card failed - {}".format(
|
|
||||||
e.data["errors"][0]["message"]
|
|
||||||
)
|
|
||||||
)
|
|
|
@ -1,229 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
""" Create Pull Request """
|
|
||||||
import base64
|
|
||||||
import common as cmn
|
|
||||||
import create_or_update_branch as coub
|
|
||||||
import create_or_update_pull_request as coupr
|
|
||||||
from git import Repo, GitCommandError
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
# Default the committer and author to the GitHub Actions bot
|
|
||||||
DEFAULT_COMMITTER = "GitHub <noreply@github.com>"
|
|
||||||
DEFAULT_AUTHOR = (
|
|
||||||
"github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"
|
|
||||||
)
|
|
||||||
DEFAULT_COMMIT_MESSAGE = "[create-pull-request] automated change"
|
|
||||||
DEFAULT_TITLE = "Changes by create-pull-request action"
|
|
||||||
DEFAULT_BODY = (
|
|
||||||
"Automated changes by "
|
|
||||||
+ "[create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action"
|
|
||||||
)
|
|
||||||
DEFAULT_BRANCH = "create-pull-request/patch"
|
|
||||||
|
|
||||||
|
|
||||||
def get_git_config_value(repo, name):
|
|
||||||
try:
|
|
||||||
return repo.git.config("--get", name)
|
|
||||||
except GitCommandError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_repository_detail(repo):
|
|
||||||
remote_origin_url = get_git_config_value(repo, "remote.origin.url")
|
|
||||||
if remote_origin_url is None:
|
|
||||||
raise ValueError("Failed to fetch 'remote.origin.url' from git config")
|
|
||||||
protocol, github_repository = cmn.parse_github_repository(remote_origin_url)
|
|
||||||
return remote_origin_url, protocol, github_repository
|
|
||||||
|
|
||||||
|
|
||||||
def git_user_config_is_set(repo):
|
|
||||||
name = get_git_config_value(repo, "user.name")
|
|
||||||
email = get_git_config_value(repo, "user.email")
|
|
||||||
|
|
||||||
if name is not None and email is not None:
|
|
||||||
print(f"Git user already configured as '{name} <{email}>'")
|
|
||||||
return True
|
|
||||||
|
|
||||||
committer_name = get_git_config_value(repo, "committer.name")
|
|
||||||
committer_email = get_git_config_value(repo, "committer.email")
|
|
||||||
author_name = get_git_config_value(repo, "author.name")
|
|
||||||
author_email = get_git_config_value(repo, "author.email")
|
|
||||||
|
|
||||||
if (
|
|
||||||
committer_name is not None
|
|
||||||
and committer_email is not None
|
|
||||||
and author_name is not None
|
|
||||||
and author_email is not None
|
|
||||||
):
|
|
||||||
print(
|
|
||||||
f"Git committer already configured as '{committer_name} <{committer_email}>'"
|
|
||||||
)
|
|
||||||
print(f"Git author already configured as '{author_name} <{author_email}>'")
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def set_committer_author(repo, committer, author):
|
|
||||||
# If either committer or author is supplied they will be cross used
|
|
||||||
if committer is None and author is not None:
|
|
||||||
print("Supplied author will also be used as the committer.")
|
|
||||||
committer = author
|
|
||||||
if author is None and committer is not None:
|
|
||||||
print("Supplied committer will also be used as the author.")
|
|
||||||
author = committer
|
|
||||||
|
|
||||||
# If no committer/author has been supplied but user configuration already
|
|
||||||
# exists in git config we can exit and use the existing config as-is.
|
|
||||||
if committer is None and author is None:
|
|
||||||
if git_user_config_is_set(repo):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Set defaults if no committer/author has been supplied
|
|
||||||
if committer is None and author is None:
|
|
||||||
committer = DEFAULT_COMMITTER
|
|
||||||
author = DEFAULT_AUTHOR
|
|
||||||
|
|
||||||
# Set git environment. This will not persist after the action completes.
|
|
||||||
committer_name, committer_email = cmn.parse_display_name_email(committer)
|
|
||||||
author_name, author_email = cmn.parse_display_name_email(author)
|
|
||||||
repo.git.update_environment(
|
|
||||||
GIT_COMMITTER_NAME=committer_name,
|
|
||||||
GIT_COMMITTER_EMAIL=committer_email,
|
|
||||||
GIT_AUTHOR_NAME=author_name,
|
|
||||||
GIT_AUTHOR_EMAIL=author_email,
|
|
||||||
)
|
|
||||||
print(f"Configured git committer as '{committer_name} <{committer_email}>'")
|
|
||||||
print(f"Configured git author as '{author_name} <{author_email}>'")
|
|
||||||
|
|
||||||
|
|
||||||
# Get required environment variables
|
|
||||||
github_token = os.environ["GITHUB_TOKEN"]
|
|
||||||
# Get environment variables with defaults
|
|
||||||
path = os.getenv("CPR_PATH", os.getcwd())
|
|
||||||
branch = os.getenv("CPR_BRANCH", DEFAULT_BRANCH)
|
|
||||||
commit_message = os.getenv("CPR_COMMIT_MESSAGE", DEFAULT_COMMIT_MESSAGE)
|
|
||||||
# Get environment variables with a default of 'None'
|
|
||||||
committer = os.environ.get("CPR_COMMITTER")
|
|
||||||
author = os.environ.get("CPR_AUTHOR")
|
|
||||||
base = os.environ.get("CPR_BASE")
|
|
||||||
|
|
||||||
# Set the repo path
|
|
||||||
repo = Repo(path)
|
|
||||||
|
|
||||||
# Determine the GitHub repository from git config
|
|
||||||
# This will be the target repository for the pull request
|
|
||||||
repo_url, protocol, github_repository = get_repository_detail(repo)
|
|
||||||
print(f"Target repository set to {github_repository}")
|
|
||||||
|
|
||||||
if protocol == "HTTPS":
|
|
||||||
print(f"::debug::Using HTTPS protocol")
|
|
||||||
# Encode and configure the basic credential for HTTPS access
|
|
||||||
basic_credential = base64.b64encode(
|
|
||||||
f"x-access-token:{github_token}".encode("utf-8")
|
|
||||||
).decode("utf-8")
|
|
||||||
# Mask the basic credential in logs and debug output
|
|
||||||
print(f"::add-mask::{basic_credential}")
|
|
||||||
repo.git.set_persistent_git_options(
|
|
||||||
c=f"http.https://github.com/.extraheader=AUTHORIZATION: basic {basic_credential}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Determine if the checked out ref is a valid base for a pull request
|
|
||||||
# The action needs the checked out HEAD ref to be a branch
|
|
||||||
# This check will fail in the following cases:
|
|
||||||
# - HEAD is detached
|
|
||||||
# - HEAD is a merge commit (pull_request events)
|
|
||||||
# - HEAD is a tag
|
|
||||||
try:
|
|
||||||
working_base = repo.git.symbolic_ref("HEAD", "--short")
|
|
||||||
except GitCommandError as e:
|
|
||||||
print(f"::debug::{e.stderr}")
|
|
||||||
print(
|
|
||||||
f"::error::The checked out ref is not a valid base for a pull request. "
|
|
||||||
+ "Unable to continue. Exiting."
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Exit if the working base is a PR branch created by this action.
|
|
||||||
# This may occur when using a PAT instead of GITHUB_TOKEN because
|
|
||||||
# a PAT allows workflow actions to trigger further events.
|
|
||||||
if working_base.startswith(branch):
|
|
||||||
print(
|
|
||||||
f"::error::Working base branch '{working_base}' was created by this action. "
|
|
||||||
+ "Unable to continue. Exiting."
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Fetch an optional environment variable to determine the branch suffix
|
|
||||||
branch_suffix = os.environ.get("CPR_BRANCH_SUFFIX")
|
|
||||||
if branch_suffix is not None:
|
|
||||||
if branch_suffix == "short-commit-hash":
|
|
||||||
# Suffix with the short SHA1 hash
|
|
||||||
branch = "{}-{}".format(branch, repo.git.rev_parse("--short", "HEAD"))
|
|
||||||
elif branch_suffix == "timestamp":
|
|
||||||
# Suffix with the current timestamp
|
|
||||||
branch = "{}-{}".format(branch, int(time.time()))
|
|
||||||
elif branch_suffix == "random":
|
|
||||||
# Suffix with a 7 character random string
|
|
||||||
branch = "{}-{}".format(branch, cmn.get_random_string())
|
|
||||||
else:
|
|
||||||
print(
|
|
||||||
f"::error::Branch suffix '{branch_suffix}' is not a valid value. "
|
|
||||||
+ "Unable to continue. Exiting."
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Output head branch
|
|
||||||
print(f"Pull request branch to create or update set to '{branch}'")
|
|
||||||
|
|
||||||
# Set the committer and author
|
|
||||||
try:
|
|
||||||
set_committer_author(repo, committer, author)
|
|
||||||
except ValueError as e:
|
|
||||||
print(f"::error::{e} " + "Unable to continue. Exiting.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Create or update the pull request branch
|
|
||||||
result = coub.create_or_update_branch(repo, repo_url, commit_message, base, branch)
|
|
||||||
|
|
||||||
if result["action"] in ["created", "updated"]:
|
|
||||||
# The branch was created or updated
|
|
||||||
print(f"Pushing pull request branch to 'origin/{branch}'")
|
|
||||||
repo.git.push("--force", repo_url, f"HEAD:refs/heads/{branch}")
|
|
||||||
|
|
||||||
# Set the base. It would have been 'None' if not specified as an input
|
|
||||||
base = result["base"]
|
|
||||||
|
|
||||||
# If there is no longer a diff with the base delete the branch and exit
|
|
||||||
if not result["diff"]:
|
|
||||||
print(f"Branch '{branch}' no longer differs from base branch '{base}'")
|
|
||||||
print(f"Closing pull request and deleting branch '{branch}'")
|
|
||||||
repo.git.push("--delete", "--force", repo_url, f"refs/heads/{branch}")
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
# Fetch optional environment variables with default values
|
|
||||||
title = os.getenv("CPR_TITLE", DEFAULT_TITLE)
|
|
||||||
body = os.getenv("CPR_BODY", DEFAULT_BODY)
|
|
||||||
|
|
||||||
# Create or update the pull request
|
|
||||||
coupr.create_or_update_pull_request(
|
|
||||||
github_token,
|
|
||||||
github_repository,
|
|
||||||
branch,
|
|
||||||
base,
|
|
||||||
title,
|
|
||||||
body,
|
|
||||||
os.environ.get("CPR_LABELS"),
|
|
||||||
os.environ.get("CPR_ASSIGNEES"),
|
|
||||||
os.environ.get("CPR_MILESTONE"),
|
|
||||||
os.environ.get("CPR_REVIEWERS"),
|
|
||||||
os.environ.get("CPR_TEAM_REVIEWERS"),
|
|
||||||
os.environ.get("CPR_PROJECT_NAME"),
|
|
||||||
os.environ.get("CPR_PROJECT_COLUMN_NAME"),
|
|
||||||
os.environ.get("CPR_DRAFT"),
|
|
||||||
os.environ.get("CPR_REQUEST_TO_PARENT"),
|
|
||||||
)
|
|
|
@ -1,4 +0,0 @@
|
||||||
setuptools==46.4.0
|
|
||||||
wheel==0.34.2
|
|
||||||
GitPython==3.1.2
|
|
||||||
PyGithub==1.51
|
|
|
@ -1,69 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
""" Test Common """
|
|
||||||
import common as cmn
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_random_string():
|
|
||||||
assert len(cmn.get_random_string()) == 7
|
|
||||||
assert len(cmn.get_random_string(length=20)) == 20
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_github_repository_success():
|
|
||||||
protocol, repository = cmn.parse_github_repository(
|
|
||||||
"https://github.com/peter-evans/create-pull-request"
|
|
||||||
)
|
|
||||||
assert protocol == "HTTPS"
|
|
||||||
assert repository == "peter-evans/create-pull-request"
|
|
||||||
|
|
||||||
protocol, repository = cmn.parse_github_repository(
|
|
||||||
"https://xxx:x-oauth-basic@github.com/peter-evans/create-pull-request"
|
|
||||||
)
|
|
||||||
assert protocol == "HTTPS"
|
|
||||||
assert repository == "peter-evans/create-pull-request"
|
|
||||||
|
|
||||||
protocol, repository = cmn.parse_github_repository(
|
|
||||||
"git@github.com:peter-evans/create-pull-request.git"
|
|
||||||
)
|
|
||||||
assert protocol == "SSH"
|
|
||||||
assert repository == "peter-evans/create-pull-request"
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_github_repository_failure():
|
|
||||||
url = "https://github.com/peter-evans"
|
|
||||||
with pytest.raises(ValueError) as e_info:
|
|
||||||
cmn.parse_github_repository(url)
|
|
||||||
assert (
|
|
||||||
e_info.value.args[0]
|
|
||||||
== f"The format of '{url}' is not a valid GitHub repository URL"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_display_name_email_success():
|
|
||||||
name, email = cmn.parse_display_name_email("abc def <abc@def.com>")
|
|
||||||
assert name == "abc def"
|
|
||||||
assert email == "abc@def.com"
|
|
||||||
|
|
||||||
name, email = cmn.parse_display_name_email(
|
|
||||||
"github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"
|
|
||||||
)
|
|
||||||
assert name == "github-actions[bot]"
|
|
||||||
assert email == "41898282+github-actions[bot]@users.noreply.github.com"
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_display_name_email_failure():
|
|
||||||
display_name_email = "abc@def.com"
|
|
||||||
with pytest.raises(ValueError) as e_info:
|
|
||||||
cmn.parse_display_name_email(display_name_email)
|
|
||||||
assert (
|
|
||||||
e_info.value.args[0]
|
|
||||||
== f"The format of '{display_name_email}' is not a valid email address with display name"
|
|
||||||
)
|
|
||||||
|
|
||||||
display_name_email = " < >"
|
|
||||||
with pytest.raises(ValueError) as e_info:
|
|
||||||
cmn.parse_display_name_email(display_name_email)
|
|
||||||
assert (
|
|
||||||
e_info.value.args[0]
|
|
||||||
== f"The format of '{display_name_email}' is not a valid email address with display name"
|
|
||||||
)
|
|
|
@ -1,757 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
""" Test Create or Update Branch """
|
|
||||||
import create_or_update_branch as coub
|
|
||||||
from git import Repo
|
|
||||||
import os
|
|
||||||
import pytest
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
# Set git repo
|
|
||||||
REPO_PATH = os.getenv("COUB_REPO_PATH", os.getcwd())
|
|
||||||
repo = Repo(REPO_PATH)
|
|
||||||
|
|
||||||
# Set git environment
|
|
||||||
author_name = "github-actions[bot]"
|
|
||||||
author_email = "41898282+github-actions[bot]@users.noreply.github.com"
|
|
||||||
committer_name = "GitHub"
|
|
||||||
committer_email = "noreply@github.com"
|
|
||||||
repo.git.update_environment(
|
|
||||||
GIT_AUTHOR_NAME=author_name,
|
|
||||||
GIT_AUTHOR_EMAIL=author_email,
|
|
||||||
GIT_COMMITTER_NAME=committer_name,
|
|
||||||
GIT_COMMITTER_EMAIL=committer_email,
|
|
||||||
)
|
|
||||||
|
|
||||||
REPO_URL = repo.git.config("--get", "remote.origin.url")
|
|
||||||
|
|
||||||
TRACKED_FILE = "tracked-file.txt"
|
|
||||||
UNTRACKED_FILE = "untracked-file.txt"
|
|
||||||
|
|
||||||
DEFAULT_BRANCH = "tests/master"
|
|
||||||
NOT_BASE_BRANCH = "tests/branch-that-is-not-the-base"
|
|
||||||
NOT_EXIST_BRANCH = "tests/branch-that-does-not-exist"
|
|
||||||
|
|
||||||
COMMIT_MESSAGE = "[create-pull-request] automated change"
|
|
||||||
BRANCH = "tests/create-pull-request/patch"
|
|
||||||
BASE = DEFAULT_BRANCH
|
|
||||||
|
|
||||||
|
|
||||||
def create_tracked_change(content=None):
|
|
||||||
if content is None:
|
|
||||||
content = str(time.time())
|
|
||||||
# Create a tracked file change
|
|
||||||
with open(os.path.join(REPO_PATH, TRACKED_FILE), "w") as f:
|
|
||||||
f.write(content)
|
|
||||||
return content
|
|
||||||
|
|
||||||
|
|
||||||
def create_untracked_change(content=None):
|
|
||||||
if content is None:
|
|
||||||
content = str(time.time())
|
|
||||||
# Create an untracked file change
|
|
||||||
with open(os.path.join(REPO_PATH, UNTRACKED_FILE), "w") as f:
|
|
||||||
f.write(content)
|
|
||||||
return content
|
|
||||||
|
|
||||||
|
|
||||||
def get_tracked_content():
|
|
||||||
# Read the content of the tracked file
|
|
||||||
with open(os.path.join(REPO_PATH, TRACKED_FILE), "r") as f:
|
|
||||||
return f.read()
|
|
||||||
|
|
||||||
|
|
||||||
def get_untracked_content():
|
|
||||||
# Read the content of the untracked file
|
|
||||||
with open(os.path.join(REPO_PATH, UNTRACKED_FILE), "r") as f:
|
|
||||||
return f.read()
|
|
||||||
|
|
||||||
|
|
||||||
def create_changes(tracked_content=None, untracked_content=None):
|
|
||||||
tracked_content = create_tracked_change(tracked_content)
|
|
||||||
untracked_content = create_untracked_change(untracked_content)
|
|
||||||
return tracked_content, untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
def create_commits(number=2, final_tracked_content=None, final_untracked_content=None):
|
|
||||||
for i in range(number):
|
|
||||||
commit_number = i + 1
|
|
||||||
if commit_number == number:
|
|
||||||
tracked_content, untracked_content = create_changes(
|
|
||||||
final_tracked_content, final_untracked_content
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
repo.git.add("-A")
|
|
||||||
repo.git.commit(m=f"Commit {commit_number}")
|
|
||||||
return tracked_content, untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module", autouse=True)
|
|
||||||
def before_after_all():
|
|
||||||
print("Before all tests")
|
|
||||||
# Check there are no local changes that might be
|
|
||||||
# destroyed by running these tests
|
|
||||||
assert not repo.is_dirty(untracked_files=True)
|
|
||||||
|
|
||||||
# Create a new default branch for the test run
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
repo.git.checkout("master")
|
|
||||||
repo.git.checkout("HEAD", b=NOT_BASE_BRANCH)
|
|
||||||
create_tracked_change()
|
|
||||||
repo.git.add("-A")
|
|
||||||
repo.git.commit(m="This commit should not appear in pr branches")
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{NOT_BASE_BRANCH}")
|
|
||||||
# Create a new default branch for the test run
|
|
||||||
repo.git.checkout("master")
|
|
||||||
repo.git.checkout("HEAD", b=DEFAULT_BRANCH)
|
|
||||||
create_tracked_change()
|
|
||||||
repo.git.add("-A")
|
|
||||||
repo.git.commit(m="Add file to be a tracked file for tests")
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
|
|
||||||
yield
|
|
||||||
|
|
||||||
print("After all tests")
|
|
||||||
repo.git.checkout("master")
|
|
||||||
# Delete the "not base branch" created for the test run
|
|
||||||
repo.git.branch("--delete", "--force", NOT_BASE_BRANCH)
|
|
||||||
repo.git.push("--delete", "--force", REPO_URL, f"refs/heads/{NOT_BASE_BRANCH}")
|
|
||||||
# Delete the default branch created for the test run
|
|
||||||
repo.git.branch("--delete", "--force", DEFAULT_BRANCH)
|
|
||||||
repo.git.push("--delete", "--force", REPO_URL, f"refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
|
|
||||||
|
|
||||||
def before_test():
|
|
||||||
print("Before test")
|
|
||||||
# Checkout the default branch
|
|
||||||
repo.git.checkout(DEFAULT_BRANCH)
|
|
||||||
|
|
||||||
|
|
||||||
def after_test(delete_remote=True):
|
|
||||||
print("After test")
|
|
||||||
# Output git log
|
|
||||||
print(repo.git.log("-5", pretty="oneline"))
|
|
||||||
# Delete the pull request branch if it exists
|
|
||||||
repo.git.checkout(DEFAULT_BRANCH)
|
|
||||||
print(f"Deleting {BRANCH}")
|
|
||||||
for branch in repo.branches:
|
|
||||||
if branch.name == BRANCH:
|
|
||||||
repo.git.branch("--delete", "--force", BRANCH)
|
|
||||||
break
|
|
||||||
if delete_remote:
|
|
||||||
print(f"Deleting origin/{BRANCH}")
|
|
||||||
for ref in repo.remotes.origin.refs:
|
|
||||||
if ref.name == f"origin/{BRANCH}":
|
|
||||||
repo.git.push("--delete", "--force", REPO_URL, f"refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch("--prune")
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
|
||||||
def before_after_tests():
|
|
||||||
before_test()
|
|
||||||
yield
|
|
||||||
after_test()
|
|
||||||
|
|
||||||
|
|
||||||
# Tests if a branch exists and can be fetched
|
|
||||||
def coub_fetch_successful():
|
|
||||||
assert coub.fetch_successful(repo, REPO_URL, NOT_BASE_BRANCH)
|
|
||||||
assert not coub.fetch_successful(repo, REPO_URL, NOT_EXIST_BRANCH)
|
|
||||||
|
|
||||||
|
|
||||||
# Tests no changes resulting in no new branch being created
|
|
||||||
def coub_no_changes_on_create():
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "none"
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with a tracked file change
|
|
||||||
def coub_tracked_changes():
|
|
||||||
# Create a tracked file change
|
|
||||||
tracked_content = create_tracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create a tracked file change
|
|
||||||
tracked_content = create_tracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with an untracked file change
|
|
||||||
def coub_untracked_changes():
|
|
||||||
# Create an untracked file change
|
|
||||||
untracked_content = create_untracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create an untracked file change
|
|
||||||
untracked_content = create_untracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with identical changes
|
|
||||||
# The pull request branch will not be updated
|
|
||||||
def coub_identical_changes():
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create identical tracked and untracked file changes
|
|
||||||
create_changes(tracked_content, untracked_content)
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "none"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with commits on the base inbetween
|
|
||||||
def coub_commits_on_base():
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the base
|
|
||||||
create_commits()
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and then an update with no changes
|
|
||||||
# This effectively reverts the branch back to match the base and results in no diff
|
|
||||||
def coub_changes_no_diff():
|
|
||||||
# Save the default branch tracked content
|
|
||||||
default_tracked_content = get_tracked_content()
|
|
||||||
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Running with no update effectively reverts the branch back to match the base
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"] == False
|
|
||||||
assert get_tracked_content() == default_tracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with commits on the base inbetween
|
|
||||||
# The changes on base effectively revert the branch back to match the base and results in no diff
|
|
||||||
def coub_commits_on_base_no_diff():
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the base
|
|
||||||
tracked_content, untracked_content = create_commits()
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
# Create the same tracked and untracked file changes that were made to the base
|
|
||||||
create_changes(tracked_content, untracked_content)
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"] == False
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with commits on the working base (during the workflow)
|
|
||||||
def coub_commits_on_working_base():
|
|
||||||
# Create commits on the working base
|
|
||||||
tracked_content, untracked_content = create_commits()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the working base
|
|
||||||
tracked_content, untracked_content = create_commits()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with changes and commits on the working base (during the workflow)
|
|
||||||
def coub_changes_and_commits_on_working_base():
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Tests create and update with changes and commits on the working base (during the workflow)
|
|
||||||
# with commits on the base inbetween
|
|
||||||
def coub_changes_and_commits_on_base_and_working_base():
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the base
|
|
||||||
create_commits()
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, None, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests no changes resulting in no new branch being created
|
|
||||||
def coub_wbnb_no_changes_on_create():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "none"
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with a tracked file change
|
|
||||||
def coub_wbnb_tracked_changes():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create a tracked file change
|
|
||||||
tracked_content = create_tracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create a tracked file change
|
|
||||||
tracked_content = create_tracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with an untracked file change
|
|
||||||
def coub_wbnb_untracked_changes():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create an untracked file change
|
|
||||||
untracked_content = create_untracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create an untracked file change
|
|
||||||
untracked_content = create_untracked_change()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with identical changes
|
|
||||||
# The pull request branch will not be updated
|
|
||||||
def coub_wbnb_identical_changes():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create identical tracked and untracked file changes
|
|
||||||
create_changes(tracked_content, untracked_content)
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "none"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with commits on the base inbetween
|
|
||||||
def coub_wbnb_commits_on_base():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the base
|
|
||||||
create_commits()
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and then an update with no changes
|
|
||||||
# This effectively reverts the branch back to match the base and results in no diff
|
|
||||||
def coub_wbnb_changes_no_diff():
|
|
||||||
# Save the default branch tracked content
|
|
||||||
default_tracked_content = get_tracked_content()
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Running with no update effectively reverts the branch back to match the base
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"] == False
|
|
||||||
assert get_tracked_content() == default_tracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with commits on the base inbetween
|
|
||||||
# The changes on base effectively revert the branch back to match the base and results in no diff
|
|
||||||
# This scenario will cause cherrypick to fail due to an empty commit.
|
|
||||||
# The commit is empty because the changes now exist on the base.
|
|
||||||
def coub_wbnb_commits_on_base_no_diff():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the base
|
|
||||||
tracked_content, untracked_content = create_commits()
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create the same tracked and untracked file changes that were made to the base
|
|
||||||
create_changes(tracked_content, untracked_content)
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"] == False
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with commits on the working base (during the workflow)
|
|
||||||
def coub_wbnb_commits_on_working_base():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create commits on the working base
|
|
||||||
tracked_content, untracked_content = create_commits()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create commits on the working base
|
|
||||||
tracked_content, untracked_content = create_commits()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with changes and commits on the working base (during the workflow)
|
|
||||||
def coub_wbnb_changes_and_commits_on_working_base():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# Working Base is Not Base (WBNB)
|
|
||||||
# Tests create and update with changes and commits on the working base (during the workflow)
|
|
||||||
# with commits on the base inbetween
|
|
||||||
def coub_wbnb_changes_and_commits_on_base_and_working_base():
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "created"
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
# Push pull request branch to remote
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
after_test(delete_remote=False)
|
|
||||||
before_test()
|
|
||||||
|
|
||||||
# Create commits on the base
|
|
||||||
create_commits()
|
|
||||||
repo.git.push("--force", REPO_URL, f"HEAD:refs/heads/{DEFAULT_BRANCH}")
|
|
||||||
repo.remotes.origin.fetch()
|
|
||||||
|
|
||||||
# Set the working base to a branch that is not the pull request base
|
|
||||||
repo.git.checkout(NOT_BASE_BRANCH)
|
|
||||||
# Create commits on the working base
|
|
||||||
create_commits()
|
|
||||||
# Create tracked and untracked file changes
|
|
||||||
tracked_content, untracked_content = create_changes()
|
|
||||||
result = coub.create_or_update_branch(repo, REPO_URL, COMMIT_MESSAGE, BASE, BRANCH)
|
|
||||||
assert result["action"] == "updated"
|
|
||||||
assert result["diff"]
|
|
||||||
assert get_tracked_content() == tracked_content
|
|
||||||
assert get_untracked_content() == untracked_content
|
|
||||||
|
|
||||||
|
|
||||||
# pytest -v -s ~/git/create-pull-request/src
|
|
||||||
|
|
||||||
test_coub_fetch_successful = coub_fetch_successful
|
|
||||||
|
|
||||||
test_coub_no_changes_on_create = coub_no_changes_on_create
|
|
||||||
test_coub_tracked_changes = coub_tracked_changes
|
|
||||||
test_coub_untracked_changes = coub_untracked_changes
|
|
||||||
test_coub_identical_changes = coub_identical_changes
|
|
||||||
test_coub_commits_on_base = coub_commits_on_base
|
|
||||||
|
|
||||||
test_coub_changes_no_diff = coub_changes_no_diff
|
|
||||||
test_coub_commits_on_base_no_diff = coub_commits_on_base_no_diff
|
|
||||||
|
|
||||||
test_coub_commits_on_working_base = coub_commits_on_working_base
|
|
||||||
test_coub_changes_and_commits_on_working_base = coub_changes_and_commits_on_working_base
|
|
||||||
test_coub_changes_and_commits_on_base_and_working_base = (
|
|
||||||
coub_changes_and_commits_on_base_and_working_base
|
|
||||||
)
|
|
||||||
|
|
||||||
# WBNB
|
|
||||||
test_coub_wbnb_no_changes_on_create = coub_wbnb_no_changes_on_create
|
|
||||||
test_coub_wbnb_tracked_changes = coub_wbnb_tracked_changes
|
|
||||||
test_coub_wbnb_untracked_changes = coub_wbnb_untracked_changes
|
|
||||||
test_coub_wbnb_identical_changes = coub_wbnb_identical_changes
|
|
||||||
test_coub_wbnb_commits_on_base = coub_wbnb_commits_on_base
|
|
||||||
|
|
||||||
test_coub_wbnb_changes_no_diff = coub_wbnb_changes_no_diff
|
|
||||||
test_coub_wbnb_commits_on_base_no_diff = coub_wbnb_commits_on_base_no_diff
|
|
||||||
|
|
||||||
test_coub_wbnb_commits_on_working_base = coub_wbnb_commits_on_working_base
|
|
||||||
test_coub_wbnb_changes_and_commits_on_working_base = (
|
|
||||||
coub_wbnb_changes_and_commits_on_working_base
|
|
||||||
)
|
|
||||||
test_coub_wbnb_changes_and_commits_on_base_and_working_base = (
|
|
||||||
coub_wbnb_changes_and_commits_on_base_and_working_base
|
|
||||||
)
|
|
|
@ -1,22 +0,0 @@
|
||||||
import * as fs from 'fs'
|
|
||||||
|
|
||||||
function hasDockerEnv(): boolean {
|
|
||||||
try {
|
|
||||||
fs.statSync('/.dockerenv')
|
|
||||||
return true
|
|
||||||
} catch (_) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasDockerCGroup(): boolean {
|
|
||||||
try {
|
|
||||||
return fs.readFileSync('/proc/self/cgroup', 'utf8').includes('docker')
|
|
||||||
} catch (_) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isDocker(): boolean {
|
|
||||||
return hasDockerEnv() || hasDockerCGroup()
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
import * as core from '@actions/core'
|
|
||||||
import * as tc from '@actions/tool-cache'
|
|
||||||
import * as path from 'path'
|
|
||||||
import * as semver from 'semver'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup for Python from the GitHub Actions tool cache
|
|
||||||
* Converted from https://github.com/actions/setup-python
|
|
||||||
*
|
|
||||||
* @param {string} versionSpec version of Python
|
|
||||||
* @param {string} arch architecture (x64|x32)
|
|
||||||
*/
|
|
||||||
export function setupPython(versionSpec: string, arch: string): Promise<void> {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const IS_WINDOWS = process.platform === 'win32'
|
|
||||||
|
|
||||||
// Find the version of Python we want in the tool cache
|
|
||||||
const installDir = tc.find('Python', versionSpec, arch)
|
|
||||||
core.debug(`installDir: ${installDir}`)
|
|
||||||
|
|
||||||
// Set paths
|
|
||||||
core.exportVariable('pythonLocation', installDir)
|
|
||||||
core.addPath(installDir)
|
|
||||||
if (IS_WINDOWS) {
|
|
||||||
core.addPath(path.join(installDir, 'Scripts'))
|
|
||||||
} else {
|
|
||||||
core.addPath(path.join(installDir, 'bin'))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IS_WINDOWS) {
|
|
||||||
// Add --user directory
|
|
||||||
// `installDir` from tool cache should look like $AGENT_TOOLSDIRECTORY/Python/<semantic version>/x64/
|
|
||||||
// So if `findLocalTool` succeeded above, we must have a conformant `installDir`
|
|
||||||
const version = path.basename(path.dirname(installDir))
|
|
||||||
const major = semver.major(version)
|
|
||||||
const minor = semver.minor(version)
|
|
||||||
|
|
||||||
const userScriptsDir = path.join(
|
|
||||||
process.env['APPDATA'] || '',
|
|
||||||
'Python',
|
|
||||||
`Python${major}${minor}`,
|
|
||||||
'Scripts'
|
|
||||||
)
|
|
||||||
core.addPath(userScriptsDir)
|
|
||||||
}
|
|
||||||
// On Linux and macOS, pip will create the --user directory and add it to PATH as needed.
|
|
||||||
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
}
|
|
Loading…
Reference in a new issue