diff --git a/dist/src/create-pull-request.py b/dist/src/create-pull-request.py deleted file mode 100755 index 4999198..0000000 --- a/dist/src/create-pull-request.py +++ /dev/null @@ -1,352 +0,0 @@ -#!/usr/bin/env python3 -""" Create Pull Request """ -import json -import os -import random -import string -import sys -import time -from git import Repo -from github import Github, GithubException - - -def get_github_event(github_event_path): - with open(github_event_path) as f: - github_event = json.load(f) - if bool(os.environ.get("DEBUG_EVENT")): - print(os.environ["GITHUB_EVENT_NAME"]) - print(json.dumps(github_event, sort_keys=True, indent=2)) - return github_event - - -def get_head_short_sha1(repo): - return repo.git.rev_parse("--short", "HEAD") - - -def get_random_suffix(size=7, chars=string.ascii_lowercase + string.digits): - return "".join(random.choice(chars) for _ in range(size)) - - -def remote_branch_exists(repo, branch): - for ref in repo.remotes.origin.refs: - if ref.name == ("origin/%s" % branch): - return True - return False - - -def get_author_default(event_name, event_data): - if event_name == "push": - email = "{head_commit[author][email]}".format(**event_data) - name = "{head_commit[author][name]}".format(**event_data) - else: - email = os.environ["GITHUB_ACTOR"] + "@users.noreply.github.com" - name = os.environ["GITHUB_ACTOR"] - return email, name - - -def get_repo_url(token, github_repository): - return "https://x-access-token:%s@github.com/%s" % (token, github_repository) - - -def checkout_branch(git, remote_exists, branch): - if remote_exists: - print("Checking out branch '%s'" % branch) - git.stash("--include-untracked") - git.checkout(branch) - try: - git.stash("pop") - except BaseException: - git.checkout("--theirs", ".") - git.reset() - else: - print("Creating new branch '%s'" % branch) - git.checkout("HEAD", b=branch) - - -def push_changes(git, token, github_repository, branch, commit_message): - git.add("-A") - git.commit(m=commit_message) - repo_url = get_repo_url(token, github_repository) - return git.push("-f", repo_url, f"HEAD:refs/heads/{branch}") - - -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("::warning::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("::warning::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 process_event(github_token, github_repository, repo, branch, base): - # Fetch optional environment variables with default values - commit_message = os.getenv( - "COMMIT_MESSAGE", "Auto-committed changes by create-pull-request action" - ) - title = os.getenv( - "PULL_REQUEST_TITLE", "Auto-generated by create-pull-request action" - ) - body = os.getenv( - "PULL_REQUEST_BODY", - "Auto-generated pull request by " - "[create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub Action", - ) - # Fetch optional environment variables with no default values - pull_request_labels = os.environ.get("PULL_REQUEST_LABELS") - pull_request_assignees = os.environ.get("PULL_REQUEST_ASSIGNEES") - pull_request_milestone = os.environ.get("PULL_REQUEST_MILESTONE") - pull_request_reviewers = os.environ.get("PULL_REQUEST_REVIEWERS") - pull_request_team_reviewers = os.environ.get("PULL_REQUEST_TEAM_REVIEWERS") - project_name = os.environ.get("PROJECT_NAME") - project_column_name = os.environ.get("PROJECT_COLUMN_NAME") - - # Push the local changes to the remote branch - print("Pushing changes to 'origin/%s'" % branch) - push_result = push_changes( - repo.git, github_token, github_repository, branch, commit_message - ) - print(push_result) - - # Create the pull request - github_repo = Github(github_token).get_repo(github_repository) - try: - pull_request = github_repo.create_pull( - title=title, body=body, base=base, head=branch - ) - print( - "Created pull request #%d (%s => %s)" % (pull_request.number, branch, base) - ) - except GithubException as e: - if e.status == 422: - # Format the branch name - head_branch = "%s:%s" % (github_repository.split("/")[0], branch) - # Get the pull request - pull_request = github_repo.get_pulls( - state="open", base=base, head=head_branch - )[0] - print( - "Updated pull request #%d (%s => %s)" - % (pull_request.number, branch, base) - ) - else: - print(str(e)) - sys.exit(1) - - # Set the output variables - os.system("echo ::set-env name=PULL_REQUEST_NUMBER::%d" % pull_request.number) - os.system("echo ::set-output name=pr_number::%d" % pull_request.number) - - # Set labels, assignees and milestone - if pull_request_labels is not None: - print("Applying labels '%s'" % pull_request_labels) - pull_request.as_issue().edit(labels=cs_string_to_list(pull_request_labels)) - if pull_request_assignees is not None: - print("Applying assignees '%s'" % pull_request_assignees) - pull_request.as_issue().edit( - assignees=cs_string_to_list(pull_request_assignees) - ) - if pull_request_milestone is not None: - print("Applying milestone '%s'" % pull_request_milestone) - milestone = github_repo.get_milestone(int(pull_request_milestone)) - pull_request.as_issue().edit(milestone=milestone) - - # Set pull request reviewers - if pull_request_reviewers is not None: - print("Requesting reviewers '%s'" % pull_request_reviewers) - try: - pull_request.create_review_request( - reviewers=cs_string_to_list(pull_request_reviewers) - ) - except GithubException as e: - # Likely caused by "Review cannot be requested from pull request - # author." - if e.status == 422: - print("Requesting reviewers failed - %s" % e.data["message"]) - - # Set pull request team reviewers - if pull_request_team_reviewers is not None: - print("Requesting team reviewers '%s'" % pull_request_team_reviewers) - pull_request.create_review_request( - team_reviewers=cs_string_to_list(pull_request_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 - %s" % e.data["errors"][0]["message"] - ) - - -# Fetch environment variables -github_token = os.environ["GITHUB_TOKEN"] -github_repository = os.environ["GITHUB_REPOSITORY"] -github_ref = os.environ["GITHUB_REF"] -event_name = os.environ["GITHUB_EVENT_NAME"] -# Get the JSON event data -event_data = get_github_event(os.environ["GITHUB_EVENT_PATH"]) - -# Get the default for author email and name -author_email, author_name = get_author_default(event_name, event_data) -# Set author name and email overrides -author_name = os.getenv("COMMIT_AUTHOR_NAME", author_name) -author_email = os.getenv("COMMIT_AUTHOR_EMAIL", author_email) -# Set committer name and email overrides -committer_name = os.getenv("COMMITTER_NAME", author_name) -committer_email = os.getenv("COMMITTER_EMAIL", author_email) - -# Set the repo to the working directory -repo = Repo(os.getcwd()) -# Set git environment. This will not persist after the action completes. -print("Configuring git author as '%s <%s>'" % (author_name, author_email)) -print("Configuring git committer as '%s <%s>'" % (committer_name, committer_email)) -repo.git.update_environment( - GIT_AUTHOR_NAME=author_name, - GIT_AUTHOR_EMAIL=author_email, - GIT_COMMITTER_NAME=committer_name, - GIT_COMMITTER_EMAIL=committer_email, -) - -# Fetch/Set the branch name -branch_prefix = os.getenv("PULL_REQUEST_BRANCH", "create-pull-request/patch") -# Fetch an optional base branch override -base_override = os.environ.get("PULL_REQUEST_BASE") - -# Set the base branch -if base_override is not None: - base = base_override - print("Overriding the base with branch '%s'" % base) - checkout_branch(repo.git, True, base) -elif github_ref.startswith("refs/pull/"): - # Check the PR is not raised from a fork of the repository - head_repo = "{pull_request[head][repo][full_name]}".format(**event_data) - if head_repo != github_repository: - print( - "::warning::Pull request was raised from a fork of the repository. " - + "Limitations on forked repositories have been imposed by GitHub Actions. " - + "Unable to continue. Exiting." - ) - sys.exit() - # Switch to the merging branch instead of the merge commit - base = os.environ["GITHUB_HEAD_REF"] - print( - "Removing the merge commit by switching to the pull request head branch '%s'" - % base - ) - checkout_branch(repo.git, True, base) -elif github_ref.startswith("refs/heads/"): - base = github_ref[11:] - print("Currently checked out base assumed to be branch '%s'" % base) -else: - print( - f"::warning::Currently checked out ref '{github_ref}' is not a valid base for a pull request. " - + "Unable to continue. Exiting." - ) - sys.exit() - -# Skip if the current branch 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 base.startswith(branch_prefix): - print("Branch '%s' was created by this action. Skipping." % base) - sys.exit() - -# Fetch an optional environment variable to determine the branch suffix -branch_suffix = os.getenv("BRANCH_SUFFIX", "short-commit-hash") -if branch_suffix == "short-commit-hash": - # Suffix with the short SHA1 hash - branch = "%s-%s" % (branch_prefix, get_head_short_sha1(repo)) -elif branch_suffix == "timestamp": - # Suffix with the current timestamp - branch = "%s-%s" % (branch_prefix, int(time.time())) -elif branch_suffix == "random": - # Suffix with the current timestamp - branch = "%s-%s" % (branch_prefix, get_random_suffix()) -elif branch_suffix == "none": - # Fixed branch name - branch = branch_prefix -else: - print("Branch suffix '%s' is not a valid value." % branch_suffix) - sys.exit(1) - -# Output head branch -print("Pull request branch to create/update set to '%s'" % branch) - -# Check if the determined head branch exists as a remote -remote_exists = remote_branch_exists(repo, branch) -if remote_exists: - print( - "Pull request branch '%s' already exists as remote branch 'origin/%s'" - % (branch, branch) - ) - if branch_suffix == "short-commit-hash": - # A remote branch already exists for the HEAD commit - print( - "Pull request branch '%s' already exists for this commit. Skipping." - % branch - ) - sys.exit() - elif branch_suffix in ["timestamp", "random"]: - # Generated branch name collision with an existing branch - print( - "Pull request branch '%s' collided with a branch of the same name. Please re-run." - % branch - ) - sys.exit(1) - -# Checkout branch -checkout_branch(repo.git, remote_exists, branch) - -# Check if there are changes to pull request -if remote_exists: - print( - "Checking for local working copy changes indicating a " - + "diff with existing pull request branch 'origin/%s'" % branch - ) -else: - print( - "Checking for local working copy changes indicating a " - + "diff with base 'origin/%s'" % base - ) - -if repo.is_dirty() or len(repo.untracked_files) > 0: - print("Modified or untracked files detected.") - process_event(github_token, github_repository, repo, branch, base) -else: - print("No modified or untracked files detected. Skipping.") diff --git a/src/create-pull-request.py b/src/create-pull-request.py deleted file mode 100755 index 4999198..0000000 --- a/src/create-pull-request.py +++ /dev/null @@ -1,352 +0,0 @@ -#!/usr/bin/env python3 -""" Create Pull Request """ -import json -import os -import random -import string -import sys -import time -from git import Repo -from github import Github, GithubException - - -def get_github_event(github_event_path): - with open(github_event_path) as f: - github_event = json.load(f) - if bool(os.environ.get("DEBUG_EVENT")): - print(os.environ["GITHUB_EVENT_NAME"]) - print(json.dumps(github_event, sort_keys=True, indent=2)) - return github_event - - -def get_head_short_sha1(repo): - return repo.git.rev_parse("--short", "HEAD") - - -def get_random_suffix(size=7, chars=string.ascii_lowercase + string.digits): - return "".join(random.choice(chars) for _ in range(size)) - - -def remote_branch_exists(repo, branch): - for ref in repo.remotes.origin.refs: - if ref.name == ("origin/%s" % branch): - return True - return False - - -def get_author_default(event_name, event_data): - if event_name == "push": - email = "{head_commit[author][email]}".format(**event_data) - name = "{head_commit[author][name]}".format(**event_data) - else: - email = os.environ["GITHUB_ACTOR"] + "@users.noreply.github.com" - name = os.environ["GITHUB_ACTOR"] - return email, name - - -def get_repo_url(token, github_repository): - return "https://x-access-token:%s@github.com/%s" % (token, github_repository) - - -def checkout_branch(git, remote_exists, branch): - if remote_exists: - print("Checking out branch '%s'" % branch) - git.stash("--include-untracked") - git.checkout(branch) - try: - git.stash("pop") - except BaseException: - git.checkout("--theirs", ".") - git.reset() - else: - print("Creating new branch '%s'" % branch) - git.checkout("HEAD", b=branch) - - -def push_changes(git, token, github_repository, branch, commit_message): - git.add("-A") - git.commit(m=commit_message) - repo_url = get_repo_url(token, github_repository) - return git.push("-f", repo_url, f"HEAD:refs/heads/{branch}") - - -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("::warning::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("::warning::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 process_event(github_token, github_repository, repo, branch, base): - # Fetch optional environment variables with default values - commit_message = os.getenv( - "COMMIT_MESSAGE", "Auto-committed changes by create-pull-request action" - ) - title = os.getenv( - "PULL_REQUEST_TITLE", "Auto-generated by create-pull-request action" - ) - body = os.getenv( - "PULL_REQUEST_BODY", - "Auto-generated pull request by " - "[create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub Action", - ) - # Fetch optional environment variables with no default values - pull_request_labels = os.environ.get("PULL_REQUEST_LABELS") - pull_request_assignees = os.environ.get("PULL_REQUEST_ASSIGNEES") - pull_request_milestone = os.environ.get("PULL_REQUEST_MILESTONE") - pull_request_reviewers = os.environ.get("PULL_REQUEST_REVIEWERS") - pull_request_team_reviewers = os.environ.get("PULL_REQUEST_TEAM_REVIEWERS") - project_name = os.environ.get("PROJECT_NAME") - project_column_name = os.environ.get("PROJECT_COLUMN_NAME") - - # Push the local changes to the remote branch - print("Pushing changes to 'origin/%s'" % branch) - push_result = push_changes( - repo.git, github_token, github_repository, branch, commit_message - ) - print(push_result) - - # Create the pull request - github_repo = Github(github_token).get_repo(github_repository) - try: - pull_request = github_repo.create_pull( - title=title, body=body, base=base, head=branch - ) - print( - "Created pull request #%d (%s => %s)" % (pull_request.number, branch, base) - ) - except GithubException as e: - if e.status == 422: - # Format the branch name - head_branch = "%s:%s" % (github_repository.split("/")[0], branch) - # Get the pull request - pull_request = github_repo.get_pulls( - state="open", base=base, head=head_branch - )[0] - print( - "Updated pull request #%d (%s => %s)" - % (pull_request.number, branch, base) - ) - else: - print(str(e)) - sys.exit(1) - - # Set the output variables - os.system("echo ::set-env name=PULL_REQUEST_NUMBER::%d" % pull_request.number) - os.system("echo ::set-output name=pr_number::%d" % pull_request.number) - - # Set labels, assignees and milestone - if pull_request_labels is not None: - print("Applying labels '%s'" % pull_request_labels) - pull_request.as_issue().edit(labels=cs_string_to_list(pull_request_labels)) - if pull_request_assignees is not None: - print("Applying assignees '%s'" % pull_request_assignees) - pull_request.as_issue().edit( - assignees=cs_string_to_list(pull_request_assignees) - ) - if pull_request_milestone is not None: - print("Applying milestone '%s'" % pull_request_milestone) - milestone = github_repo.get_milestone(int(pull_request_milestone)) - pull_request.as_issue().edit(milestone=milestone) - - # Set pull request reviewers - if pull_request_reviewers is not None: - print("Requesting reviewers '%s'" % pull_request_reviewers) - try: - pull_request.create_review_request( - reviewers=cs_string_to_list(pull_request_reviewers) - ) - except GithubException as e: - # Likely caused by "Review cannot be requested from pull request - # author." - if e.status == 422: - print("Requesting reviewers failed - %s" % e.data["message"]) - - # Set pull request team reviewers - if pull_request_team_reviewers is not None: - print("Requesting team reviewers '%s'" % pull_request_team_reviewers) - pull_request.create_review_request( - team_reviewers=cs_string_to_list(pull_request_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 - %s" % e.data["errors"][0]["message"] - ) - - -# Fetch environment variables -github_token = os.environ["GITHUB_TOKEN"] -github_repository = os.environ["GITHUB_REPOSITORY"] -github_ref = os.environ["GITHUB_REF"] -event_name = os.environ["GITHUB_EVENT_NAME"] -# Get the JSON event data -event_data = get_github_event(os.environ["GITHUB_EVENT_PATH"]) - -# Get the default for author email and name -author_email, author_name = get_author_default(event_name, event_data) -# Set author name and email overrides -author_name = os.getenv("COMMIT_AUTHOR_NAME", author_name) -author_email = os.getenv("COMMIT_AUTHOR_EMAIL", author_email) -# Set committer name and email overrides -committer_name = os.getenv("COMMITTER_NAME", author_name) -committer_email = os.getenv("COMMITTER_EMAIL", author_email) - -# Set the repo to the working directory -repo = Repo(os.getcwd()) -# Set git environment. This will not persist after the action completes. -print("Configuring git author as '%s <%s>'" % (author_name, author_email)) -print("Configuring git committer as '%s <%s>'" % (committer_name, committer_email)) -repo.git.update_environment( - GIT_AUTHOR_NAME=author_name, - GIT_AUTHOR_EMAIL=author_email, - GIT_COMMITTER_NAME=committer_name, - GIT_COMMITTER_EMAIL=committer_email, -) - -# Fetch/Set the branch name -branch_prefix = os.getenv("PULL_REQUEST_BRANCH", "create-pull-request/patch") -# Fetch an optional base branch override -base_override = os.environ.get("PULL_REQUEST_BASE") - -# Set the base branch -if base_override is not None: - base = base_override - print("Overriding the base with branch '%s'" % base) - checkout_branch(repo.git, True, base) -elif github_ref.startswith("refs/pull/"): - # Check the PR is not raised from a fork of the repository - head_repo = "{pull_request[head][repo][full_name]}".format(**event_data) - if head_repo != github_repository: - print( - "::warning::Pull request was raised from a fork of the repository. " - + "Limitations on forked repositories have been imposed by GitHub Actions. " - + "Unable to continue. Exiting." - ) - sys.exit() - # Switch to the merging branch instead of the merge commit - base = os.environ["GITHUB_HEAD_REF"] - print( - "Removing the merge commit by switching to the pull request head branch '%s'" - % base - ) - checkout_branch(repo.git, True, base) -elif github_ref.startswith("refs/heads/"): - base = github_ref[11:] - print("Currently checked out base assumed to be branch '%s'" % base) -else: - print( - f"::warning::Currently checked out ref '{github_ref}' is not a valid base for a pull request. " - + "Unable to continue. Exiting." - ) - sys.exit() - -# Skip if the current branch 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 base.startswith(branch_prefix): - print("Branch '%s' was created by this action. Skipping." % base) - sys.exit() - -# Fetch an optional environment variable to determine the branch suffix -branch_suffix = os.getenv("BRANCH_SUFFIX", "short-commit-hash") -if branch_suffix == "short-commit-hash": - # Suffix with the short SHA1 hash - branch = "%s-%s" % (branch_prefix, get_head_short_sha1(repo)) -elif branch_suffix == "timestamp": - # Suffix with the current timestamp - branch = "%s-%s" % (branch_prefix, int(time.time())) -elif branch_suffix == "random": - # Suffix with the current timestamp - branch = "%s-%s" % (branch_prefix, get_random_suffix()) -elif branch_suffix == "none": - # Fixed branch name - branch = branch_prefix -else: - print("Branch suffix '%s' is not a valid value." % branch_suffix) - sys.exit(1) - -# Output head branch -print("Pull request branch to create/update set to '%s'" % branch) - -# Check if the determined head branch exists as a remote -remote_exists = remote_branch_exists(repo, branch) -if remote_exists: - print( - "Pull request branch '%s' already exists as remote branch 'origin/%s'" - % (branch, branch) - ) - if branch_suffix == "short-commit-hash": - # A remote branch already exists for the HEAD commit - print( - "Pull request branch '%s' already exists for this commit. Skipping." - % branch - ) - sys.exit() - elif branch_suffix in ["timestamp", "random"]: - # Generated branch name collision with an existing branch - print( - "Pull request branch '%s' collided with a branch of the same name. Please re-run." - % branch - ) - sys.exit(1) - -# Checkout branch -checkout_branch(repo.git, remote_exists, branch) - -# Check if there are changes to pull request -if remote_exists: - print( - "Checking for local working copy changes indicating a " - + "diff with existing pull request branch 'origin/%s'" % branch - ) -else: - print( - "Checking for local working copy changes indicating a " - + "diff with base 'origin/%s'" % base - ) - -if repo.is_dirty() or len(repo.untracked_files) > 0: - print("Modified or untracked files detected.") - process_event(github_token, github_repository, repo, branch, base) -else: - print("No modified or untracked files detected. Skipping.")