Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

auto-release-pr #1

Merged
merged 18 commits into from
Aug 24, 2020
15 changes: 15 additions & 0 deletions .github/workflows/auto-release-pr-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Test auto-release-pr
on:
# To test, comment-in following line. The PR body will be generated.
#pull_request:
# dummy trigger
repository_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./auto-release-pr
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}
releasePRNumber: ${{ github.event.pull_request.number }}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# github-actions
Shared Github Actions

- [`auto-release-pr`](https://github.com/ratel-pay/github-actions/blob/master/auto-release-pr): リリースPRの本文を自動で更新
8 changes: 8 additions & 0 deletions auto-release-pr/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM python:3

ADD . /app
WORKDIR /app

RUN pip install -r requirements.txt

CMD ["python", "/app/release-pr.py"]
70 changes: 70 additions & 0 deletions auto-release-pr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# auto-release-pr

リリースPull Requestの本文を自動で書き換えるActionです。

以下の動作をします。

1. 対象となるリリースPRを探索、見つからなければ新たに作成します。
1. リリースPRに含まれる各コミットのコミットメッセージから含まれているPRの一覧を取得します。
1. リリースPRの本文を更新して、前後の差分をコメントに残します。

## Inputs
| パラメータ | Required | Default | |
|-|-|-|-|
| `githubToken` | ✔ | | GitHub Token。PRの探索や更新に利用されます。 |
| `baseBranch` | | `release` | リリースPRのBase Branch。PRの探索や作成時に利用されます。 |
| `headBranch` | | `master` | リリースPRのHead Branch。PRの探索や作成時に利用されます。 |
| `releasePRNumber` | | | リリースPRの番号。 `releasePRNumber` が指定されると `baseBranch`/`headBranch` は無視されます。 |
| `bodyTemplate` | | [`action.yml`](https://github.com/ratel-pay/github-actions/blob/master/auto-release-pr/action.yml) を参照 | PR本文の生成テンプレート。テンプレート内の `{summary}` が差分の箇条書きに置き換えられます。 |
| `commentTemplate` | | [`action.yml`](https://github.com/ratel-pay/github-actions/blob/master/auto-release-pr/action.yml) を参照 | 本文の更新差分のコメントのテンプレート。テンプレート内の `{diff}` が差分表示に置き換えられます。 |

## Usage

ブランチ運用フローによって2つの使い方があります。

### `master` ブランチを直接 `release` ブランチに取り込む場合

`master` 向きのPRがマージされるたびに、 `master` から `release` ブランチに向いているPRを探索 or 作成し、その本文を置き換えます。

```yaml
on:
pull_request:
types:
- closed
branches:
- master
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ratel-pay/github-actions/auto-release-pr@master
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}
# Set if needed
# baseBranch: release
# headBranch: master
```

### リリースのたびにブランチを切ってPull Requestを作成している場合

`release` に向けたPRのBranchが更新されるたびに、その本文を置き換えます。

```yaml
on:
pull_request:
types:
- opened
- synchronized
branches:
- release
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ratel-pay/github-actions/auto-release-pr@master
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}
releasePRNumber: ${{ github.event.pull_request.number }}
```
49 changes: 49 additions & 0 deletions auto-release-pr/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Update Release PR
description: Find or create release Pull Request and update its body automatically.
inputs:
githubToken:
description: GitHub Token
required: true
baseBranch:
description: |
The base branch of Pull Request to find.
It will be ignored if `releasePRNumber` is passed.
required: true
default: release
headBranch:
description: |
The head branch of Pull Request to find.
It will be ignored if `releasePRNumber` is passed.
required: true
default: master
releasePRNumber:
description: The number of release Pull Request.
required: false
bodyTemplate:
description: |
The template of generating release Pull Request.
`{summary}` will be replaced with generating body.
required: true
default: |
## Changes

{summary}
commentTemplate:
description: |
The template of generating comment.
`{diff}` will be replaced with diff.
required: true
default: |
PR body is updated!
<details><summary>diff</summary>
<p>

```diff
{diff}
```

</p>
</detail>
runs:
using: "docker"
image: "Dockerfile"
89 changes: 89 additions & 0 deletions auto-release-pr/release-pr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import github

from typing import Optional
import difflib
import os
import re
import sys


GITHUB_TOKEN: str = os.environ['INPUT_GITHUBTOKEN']
REPO_NAME: str = os.environ['GITHUB_REPOSITORY']
BASE_BRANCH: str = os.environ['INPUT_BASEBRANCH']
HEAD_BRANCH: str = os.environ['INPUT_HEADBRANCH']
RELEASE_PR_NUMBER: Optional[str] = os.environ.get('INPUT_RELEASEPRNUMBER')

BODY_TEMPLATE: str = os.environ['INPUT_BODYTEMPLATE']
COMMENT_TEMPLATE: str = os.environ['INPUT_COMMENTTEMPLATE']


# release 向きの最新 PR を取得
def find_latest_release_pr(repo: github.Repository.Repository, base: str, head: str) -> Optional[github.PullRequest.PullRequest]:
prs = repo.get_pulls(state='open', base=base, head=head, sort='created', direction='desc')

if prs.totalCount > 0:
return prs[0]
else:
return None

# release 向きの最新 PR を取得を探して、なかったら作成する
def find_or_create_release_pr(repo: github.Repository.Repository, base: str, head: str, number: Optional[str]) -> github.PullRequest.PullRequest:
if number:
return repo.get_pull(int(number))

latest = find_latest_release_pr(repo)
if latest:
return latest
else:
return repo.create_pull(title='[リリース]',
body='',
base=base,
head=head,
draft=True)

# PR のコミットメッセージから含まれる PR を探して新しいの PR の body を作る
def make_new_body(pr: github.PullRequest.PullRequest, template: str) -> Optional[str]:
commit_messages = [cm.commit.message for cm in pr.get_commits()]
merge_commit_messages = [m for m in commit_messages if m.startswith("Merge pull request")]

# 複数行のコミットメッセージから箇条書きの一行を生成する
def convert_to_body_line(message: str) -> str:
lines = message.splitlines()

number = re.search(r'#\d+', lines[0]).group()
title = lines[2]

return f'- {number}: {title}'

body_lines = '\n'.join(map(convert_to_body_line, merge_commit_messages))
if len(body_lines) > 0:
return template.format(summary=body_lines)
else:
return None

def main():
g = github.Github(GITHUB_TOKEN)
repo = g.get_repo(REPO_NAME)
release_pr = find_or_create_release_pr(repo, base=BASE_BRANCH, head=HEAD_BRANCH, number=RELEASE_PR_NUMBER)

# body を生成
new_body = make_new_body(release_pr, template=BODY_TEMPLATE)
if not new_body:
print("Failed to generate new PR body.")
sys.exit(1)

# diff を生成
old_body_lines = release_pr.body.splitlines()
new_body_lines = new_body.splitlines()
diff = '\n'.join(difflib.unified_diff(old_body_lines, new_body_lines))

# PR 本文を更新
release_pr.edit(body=new_body)

# comment に diff を残す
comment_body = COMMENT_TEMPLATE.format(diff=diff)
release_pr.as_issue().create_comment(comment_body)


if __name__ == "__main__":
main()
9 changes: 9 additions & 0 deletions auto-release-pr/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
certifi==2020.6.20
chardet==3.0.4
Deprecated==1.2.10
idna==2.10
PyGithub==1.53
PyJWT==1.7.1
requests==2.24.0
urllib3==1.25.10
wrapt==1.12.1