Skip to content

Commit

Permalink
Showing 29 changed files with 687 additions and 481 deletions.
178 changes: 178 additions & 0 deletions .github/update-release-branch.py
@@ -0,0 +1,178 @@
import datetime
from github import Github
import random
import requests
import subprocess
import sys

# The branch being merged from.
# This is the one that contains day-to-day development work.
MASTER_BRANCH = 'master'
# The branch being merged into.
# This is the release branch that users reference.
LATEST_RELEASE_BRANCH = 'v1'
# Name of the remote
ORIGIN = 'origin'

# Runs git with the given args and returns the stdout.
# Raises an error if git does not exit successfully.
def run_git(*args):
cmd = ['git', *args]
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if (p.returncode != 0):
raise Exception('Call to ' + ' '.join(cmd) + ' exited with code ' + str(p.returncode) + ' stderr:' + p.stderr.decode('ascii'))
return p.stdout.decode('ascii')

# Returns true if the given branch exists on the origin remote
def branch_exists_on_remote(branch_name):
return run_git('ls-remote', '--heads', ORIGIN, branch_name).strip() != ''

# Opens a PR from the given branch to the release branch
def open_pr(repo, all_commits, short_master_sha, branch_name):
# Sort the commits into the pull requests that introduced them,
# and any commits that don't have a pull request
pull_requests = []
commits_without_pull_requests = []
for commit in all_commits:
pr = get_pr_for_commit(repo, commit)

if pr is None:
commits_without_pull_requests.append(commit)
elif not any(p for p in pull_requests if p.number == pr.number):
pull_requests.append(pr)

print('Found ' + str(len(pull_requests)) + ' pull requests')
print('Found ' + str(len(commits_without_pull_requests)) + ' commits not in a pull request')

# Sort PRs and commits by age
sorted(pull_requests, key=lambda pr: pr.number)
sorted(commits_without_pull_requests, key=lambda c: c.commit.author.date)

# Start constructing the body text
body = 'Merging ' + short_master_sha + ' into ' + LATEST_RELEASE_BRANCH

conductor = get_conductor(repo, pull_requests, commits_without_pull_requests)
body += '\n\nConductor for this PR is @' + conductor

# List all PRs merged
if len(pull_requests) > 0:
body += '\n\nContains the following pull requests:'
for pr in pull_requests:
merger = get_merger_of_pr(repo, pr)
body += '\n- #' + str(pr.number)
body += ' - ' + pr.title
body += ' (@' + merger + ')'

# List all commits not part of a PR
if len(commits_without_pull_requests) > 0:
body += '\n\nContains the following commits not from a pull request:'
for commit in commits_without_pull_requests:
body += '\n- ' + commit.sha
body += ' - ' + get_truncated_commit_message(commit)
body += ' (@' + commit.author.login + ')'

title = 'Merge ' + MASTER_BRANCH + ' into ' + LATEST_RELEASE_BRANCH

# Create the pull request
pr = repo.create_pull(title=title, body=body, head=branch_name, base=LATEST_RELEASE_BRANCH)
print('Created PR #' + str(pr.number))

# Assign the conductor
pr.add_to_assignees(conductor)
print('Assigned PR to ' + conductor)

# Gets the person who should be in charge of the mergeback PR
def get_conductor(repo, pull_requests, other_commits):
# If there are any PRs then use whoever merged the last one
if len(pull_requests) > 0:
return get_merger_of_pr(repo, pull_requests[-1])

# Otherwise take the author of the latest commit
return other_commits[-1].author.login

# Gets a list of the SHAs of all commits that have happened on master
# since the release branched off.
# This will not include any commits that exist on the release branch
# that aren't on master.
def get_commit_difference(repo):
commits = run_git('log', '--pretty=format:%H', ORIGIN + '/' + LATEST_RELEASE_BRANCH + '...' + MASTER_BRANCH).strip().split('\n')

# Convert to full-fledged commit objects
commits = [repo.get_commit(c) for c in commits]

# Filter out merge commits for PRs
return list(filter(lambda c: not is_pr_merge_commit(c), commits))

# Is the given commit the automatic merge commit from when merging a PR
def is_pr_merge_commit(commit):
return commit.committer.login == 'web-flow' and len(commit.parents) > 1

# Gets a copy of the commit message that should display nicely
def get_truncated_commit_message(commit):
message = commit.commit.message.split('\n')[0]
if len(message) > 60:
return message[:57] + '...'
else:
return message

# Converts a commit into the PR that introduced it to the master branch.
# Returns the PR object, or None if no PR could be found.
def get_pr_for_commit(repo, commit):
prs = commit.get_pulls()

if prs.totalCount > 0:
# In the case that there are multiple PRs, return the earliest one
prs = list(prs)
sorted(prs, key=lambda pr: int(pr.number))
return prs[0]
else:
return None

# Get the person who merged the pull request.
# For most cases this will be the same as the author, but for PRs opened
# by external contributors getting the merger will get us the GitHub
# employee who reviewed and merged the PR.
def get_merger_of_pr(repo, pr):
return repo.get_commit(pr.merge_commit_sha).author.login

def main():
if len(sys.argv) != 3:
raise Exception('Usage: update-release.branch.py <github token> <repository nwo>')
github_token = sys.argv[1]
repository_nwo = sys.argv[2]

repo = Github(github_token).get_repo(repository_nwo)

# Print what we intend to go
print('Considering difference between ' + MASTER_BRANCH + ' and ' + LATEST_RELEASE_BRANCH)
short_master_sha = run_git('rev-parse', '--short', MASTER_BRANCH).strip()
print('Current head of ' + MASTER_BRANCH + ' is ' + short_master_sha)

# See if there are any commits to merge in
commits = get_commit_difference(repo)
if len(commits) == 0:
print('No commits to merge from ' + MASTER_BRANCH + ' to ' + LATEST_RELEASE_BRANCH)
return

# The branch name is based off of the name of branch being merged into
# and the SHA of the branch being merged from. Thus if the branch already
# exists we can assume we don't need to recreate it.
new_branch_name = 'update-' + LATEST_RELEASE_BRANCH + '-' + short_master_sha
print('Branch name is ' + new_branch_name)

# Check if the branch already exists. If so we can abort as this script
# has already run on this combination of branches.
if branch_exists_on_remote(new_branch_name):
print('Branch ' + new_branch_name + ' already exists. Nothing to do.')
return

# Create the new branch and push it to the remote
print('Creating branch ' + new_branch_name)
run_git('checkout', '-b', new_branch_name, MASTER_BRANCH)
run_git('push', ORIGIN, new_branch_name)

# Open a PR to update the branch
open_pr(repo, commits, short_master_sha, new_branch_name)

if __name__ == '__main__':
main()
28 changes: 28 additions & 0 deletions .github/workflows/update-release-branch.yml
@@ -0,0 +1,28 @@
name: Update release branch
on:
schedule:
- cron: 0 9 * * 1
repository_dispatch:
types: [update-release-branch]

jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
# Need full history so we calculate diffs
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.5

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install PyGithub==1.51 requests
- name: Update release branch
run: python .github/update-release-branch.py ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }}
2 changes: 1 addition & 1 deletion README.md
@@ -1,6 +1,6 @@
# CodeQL Action

This action runs GitHub's industry-leading static analysis engine, CodeQL, against a repository's source code to find security vulnerabilities. It then automatically uploads the results to GitHub so they can be displayed in the repository's security tab. CodeQL runs an extensible set of [queries](https://github.com/semmle/ql), which have been developed by the community and the [GitHub Security Lab](https://securitylab.github.com/) to find common vulnerabilities in your code.
This action runs GitHub's industry-leading static analysis engine, CodeQL, against a repository's source code to find security vulnerabilities. It then automatically uploads the results to GitHub so they can be displayed in the repository's security tab. CodeQL runs an extensible set of [queries](https://github.com/github/codeql), which have been developed by the community and the [GitHub Security Lab](https://securitylab.github.com/) to find common vulnerabilities in your code.

## License

2 changes: 1 addition & 1 deletion lib/analysis-paths.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

125 changes: 83 additions & 42 deletions lib/config-utils.js
2 changes: 1 addition & 1 deletion lib/config-utils.js.map
147 changes: 40 additions & 107 deletions lib/config-utils.test.js
2 changes: 1 addition & 1 deletion lib/config-utils.test.js.map
2 changes: 1 addition & 1 deletion lib/external-queries.js
2 changes: 1 addition & 1 deletion lib/external-queries.js.map
2 changes: 1 addition & 1 deletion lib/external-queries.test.js
2 changes: 1 addition & 1 deletion lib/external-queries.test.js.map
23 changes: 21 additions & 2 deletions lib/finalize-db.js
2 changes: 1 addition & 1 deletion lib/finalize-db.js.map
13 changes: 7 additions & 6 deletions lib/setup-tracer.js
2 changes: 1 addition & 1 deletion lib/setup-tracer.js.map
102 changes: 48 additions & 54 deletions lib/upload-lib.js

0 comments on commit fcb696e

Please sign in to comment.