ci: fix typo squasher by changing trigger to "pull_request_target" (#15357)

The "pull_request" trigger only enables read-access for forks,
"pull_request_target" is required if a fork is to be a trigger. Also
changed the python script to reflect this change.
This commit is contained in:
dundargoc
2021-08-13 15:18:15 +02:00
committed by GitHub
parent 6f0d4ccc43
commit ce172d8d4a
2 changed files with 109 additions and 54 deletions

View File

@@ -1,7 +1,7 @@
name: Squash Typo Pull Requests name: Squash Typo Pull Requests
on: on:
pull_request: pull_request_target:
types: labeled types: labeled
concurrency: concurrency:
group: ${{ github.workflow }} group: ${{ github.workflow }}
@@ -21,7 +21,6 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
fetch-depth: 0 fetch-depth: 0
ref: master
- uses: actions/setup-python@v2 - uses: actions/setup-python@v2
- name: Setup git config - name: Setup git config
@@ -30,3 +29,5 @@ jobs:
git config --global user.email 'marvim@users.noreply.github.com' git config --global user.email 'marvim@users.noreply.github.com'
- run: python scripts/squash_typos.py - run: python scripts/squash_typos.py
env:
PR_NUMBER: ${{ github.event.number }}

View File

@@ -7,17 +7,16 @@ This script squashes a PR tagged with the "typo" label into a single, dedicated
""" """
import subprocess import subprocess
import sys
import os import os
import re
def get_authors_and_emails_from_pr(): def get_authors_and_emails_from_pr():
""" """
For a given PR number, returns all contributing authors and their emails Return all contributing authors and their emails for the PR on current branch.
for that PR. This includes co-authors, meaning that if two authors are This includes co-authors, meaning that if two authors are credited for a
credited for a single commit, which is possible with GitHub, then both will single commit, which is possible with GitHub, then both will get credited.
get credited.
""" """
@@ -33,44 +32,67 @@ def get_authors_and_emails_from_pr():
text=True, text=True,
).splitlines() ).splitlines()
return [(author, mail) for author, mail in zip(authors, emails)] authors_and_emails_unique = {
(author, mail) for author, mail in zip(authors, emails)
}
return sorted(authors_and_emails_unique)
def rebase_onto_pr(pr, squash_branch): def rebase_onto_pr():
""" """
Add all commits from PR into current branch. This is done by rebasing Rebase current branch onto the PR.
current branch onto the PR.
""" """
# Check out the pull request. # Check out the pull request.
subprocess.call(["gh", "pr", "checkout", pr]) subprocess.call(["gh", "pr", "checkout", os.environ["PR_NUMBER"]])
pr_branch_name = subprocess.check_output(
["git", "branch", "--show-current"], text=True
).strip()
# Change back to the original branch. # Change back to the original branch.
subprocess.call(["git", "switch", squash_branch]) subprocess.call(["git", "switch", "-"])
# Rebase onto the pull request, aka include the commits in the pull # Rebase onto the pull request, aka include the commits in the pull request
# request in the current branch. # in the current branch. Abort with error message if rebase fails.
subprocess.call(["git", "rebase", pr_branch_name])
try:
subprocess.check_call(["git", "rebase", "-"])
except subprocess.CalledProcessError:
subprocess.call(["git", "rebase", "--abort"])
squash_url = subprocess.check_output(
["gh", "pr", "view", "--json", "url", "--jq", ".url"], text=True
).strip()
subprocess.call(
[
"gh",
"pr",
"comment",
os.environ["PR_NUMBER"],
"--body",
f"Your edit conflicts with an already scheduled fix ({squash_url}). \
Please wait for an adult to come and help you.",
]
)
sys.exit(
f"\n\nERROR: Your edit conflicts with an already scheduled fix \
{squash_url} \n\n"
)
def squash_all_commits(): def squash_all_commits():
""" """
Squash all commits into a single commit. Credit all authors by name and Squash all commits on the PR into a single commit. Credit all authors by
email. name and email.
""" """
authors_and_emails = get_authors_and_emails_from_pr() default_branch = f"{os.environ['GITHUB_BASE_REF']}"
subprocess.call(["git", "reset", "--soft", f"{os.environ['GITHUB_BASE_REF']}"]) subprocess.call(["git", "reset", "--soft", default_branch])
authors_and_emails = sorted(set(authors_and_emails)) authors_and_emails = get_authors_and_emails_from_pr()
commit_message_coauthors = "\n" + "\n".join( commit_message_coauthors = "\n" + "\n".join(
[f"Co-authored-by: {i[0]} <{i[1]}>" for i in authors_and_emails] [f"Co-authored-by: {i[0]} <{i[1]}>" for i in authors_and_emails]
) )
@@ -80,6 +102,12 @@ def squash_all_commits():
def force_push(branch): def force_push(branch):
"""
Like the name implies, force push <branch>.
"""
gh_actor = os.environ["GITHUB_ACTOR"] gh_actor = os.environ["GITHUB_ACTOR"]
gh_token = os.environ["GITHUB_TOKEN"] gh_token = os.environ["GITHUB_TOKEN"]
gh_repo = os.environ["GITHUB_REPOSITORY"] gh_repo = os.environ["GITHUB_REPOSITORY"]
@@ -94,40 +122,60 @@ def force_push(branch):
) )
def main(): def checkout_branch(branch):
squash_branch = "marvim/squash-typos" """
all_pr_urls = ""
pr_number = re.sub(r"\D", "", os.environ["GITHUB_REF"]) Create and checkout <branch>. Check if branch exists on remote, if so then
sync local branch to remote.
Return True if remote branch exists, else False.
"""
# FIXME I'm not sure why the local branch isn't tracking the remote branch
# automatically. This works but I'm pretty sure it can be done in a more
# "elegant" fashion
show_ref_output = subprocess.check_output(["git", "show-ref"], text=True).strip() show_ref_output = subprocess.check_output(["git", "show-ref"], text=True).strip()
if squash_branch in show_ref_output: if branch in show_ref_output:
subprocess.call( subprocess.call(["git", "checkout", "-b", branch, f"origin/{branch}"])
["git", "checkout", "-b", squash_branch, f"origin/{squash_branch}"] return True
)
squash_branch_exists = True
subprocess.call(["git", "checkout", "-b", branch])
return False
def get_all_pr_urls(squash_branch_exists):
"""
Return a list of URLs for the pull requests with the typo fixes. If a
squash branch exists then extract the URLs from the body text.
"""
all_pr_urls = ""
if squash_branch_exists:
all_pr_urls += subprocess.check_output( all_pr_urls += subprocess.check_output(
["gh", "pr", "view", "--json", "body", "--jq", ".body"], text=True ["gh", "pr", "view", "--json", "body", "--jq", ".body"], text=True
) )
else:
subprocess.call(["git", "checkout", "-b", squash_branch])
squash_branch_exists = False
all_pr_urls += subprocess.check_output( all_pr_urls += subprocess.check_output(
["gh", "pr", "view", pr_number, "--json", "url", "--jq", ".url"], text=True ["gh", "pr", "view", os.environ["PR_NUMBER"], "--json", "url", "--jq", ".url"],
text=True,
).strip() ).strip()
rebase_onto_pr(pr_number, squash_branch) return all_pr_urls
def main():
squash_branch = "marvim/squash-typos"
squash_branch_exists = checkout_branch(squash_branch)
rebase_onto_pr()
force_push(squash_branch) force_push(squash_branch)
subprocess.call(["gh", "pr", "close", pr_number])
squash_all_commits()
force_push(squash_branch)
if not squash_branch_exists:
subprocess.call( subprocess.call(
[ [
"gh", "gh",
@@ -141,8 +189,14 @@ def main():
] ]
) )
squash_all_commits()
force_push(squash_branch)
all_pr_urls = get_all_pr_urls(squash_branch_exists)
subprocess.call(["gh", "pr", "edit", "--add-label", "typo", "--body", all_pr_urls]) subprocess.call(["gh", "pr", "edit", "--add-label", "typo", "--body", all_pr_urls])
subprocess.call(["gh", "pr", "close", os.environ["PR_NUMBER"]])
if __name__ == "__main__": if __name__ == "__main__":
main() main()