[#39] Add Zuul job for GitHub Issues integration
Adds a post job to update related issues in Github on change merges. If a change contains a "Closes: #X" tag, issue X will be closed on merge. If a change contains a "Relates-To: #X" or "[#X]" tag, a comment will be made on the associated issue to indicate the change was merged and that the issue may be closeable. Closes: #39 Change-Id: Ide9a4d53de7be0e467422938e4e8067fb41ce036
This commit is contained in:
parent
3ca4d7d266
commit
25691da17a
@ -60,9 +60,19 @@ to the issue with a link to your change on Gerrit and change the "wip" label
|
|||||||
to a "ready for review" label to indicate to the community that you are
|
to a "ready for review" label to indicate to the community that you are
|
||||||
seeking reviews.
|
seeking reviews.
|
||||||
|
|
||||||
In your commit message, be sure to include a bracketed tag for the issue you
|
In your commit message, be sure to include a reference for the issue you
|
||||||
are addressing from GitHub Issues. For example, if you are addressing the issue
|
are addressing from GitHub Issues. There are three ways of doing this:
|
||||||
\#17, you would start your commit message with `[#17] <Commit Message>`.
|
|
||||||
|
1. Add a statement in your commit message in the format of `Relates-To: #X`.
|
||||||
|
This will add a link on issue "#X" to your change.
|
||||||
|
2. Add a statement in your commit message in the format of `Closes: #X`.
|
||||||
|
This will add a link on issue "#X" to your change and will close the issue when
|
||||||
|
your change merges.
|
||||||
|
3. Add a bracketed tag at the beginning of your commit message in the format of
|
||||||
|
`[#X] <begin commit message>`. This will add a link on issue "#X" to your
|
||||||
|
change. This method is considered a fallback in lieu of the other two methods.
|
||||||
|
|
||||||
|
Any issue references should be evaluated within 15 minutes of being uploaded.
|
||||||
|
|
||||||
## Reviewing Changes
|
## Reviewing Changes
|
||||||
|
|
||||||
|
27
playbooks/airship-airshipctl-update-github-issues.yaml
Normal file
27
playbooks/airship-airshipctl-update-github-issues.yaml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
- hosts: primary
|
||||||
|
tasks:
|
||||||
|
- name: Install script dependencies
|
||||||
|
pip:
|
||||||
|
name:
|
||||||
|
- PyGithub==1.46
|
||||||
|
executable: pip3
|
||||||
|
- name: Run python script
|
||||||
|
script: >
|
||||||
|
zuul.d/scripts/update_github_issues.py "{{ github_credentials.username }}" \
|
||||||
|
"{{ github_credentials.password }}" \
|
||||||
|
"{{ zuul.message }}" \
|
||||||
|
"{{ zuul.items[0].change_url }}"
|
||||||
|
args:
|
||||||
|
executable: python3
|
@ -24,6 +24,15 @@
|
|||||||
run: playbooks/airship-airshipctl-lint-unit.yaml
|
run: playbooks/airship-airshipctl-lint-unit.yaml
|
||||||
nodeset: airship-airshipctl-single-node
|
nodeset: airship-airshipctl-single-node
|
||||||
|
|
||||||
|
- job:
|
||||||
|
name: airship-airshipctl-update-github-issues
|
||||||
|
description: Updates and/or closes related issues on Github on merge
|
||||||
|
run: playbooks/airship-airshipctl-update-github-issues.yaml
|
||||||
|
nodeset: airship-airshipctl-single-node
|
||||||
|
secrets:
|
||||||
|
- name: github_credentials
|
||||||
|
secret: airship-airshipctl-airshipit-github-username-password
|
||||||
|
|
||||||
- job:
|
- job:
|
||||||
name: airship-airshipctl-build-image
|
name: airship-airshipctl-build-image
|
||||||
nodeset: airship-airshipctl-single-node
|
nodeset: airship-airshipctl-single-node
|
||||||
|
@ -30,3 +30,4 @@
|
|||||||
- airship-airshipctl-publish-docs
|
- airship-airshipctl-publish-docs
|
||||||
- airship-airshipctl-publish-image
|
- airship-airshipctl-publish-image
|
||||||
- airship-airshipctl-upload-git-mirror
|
- airship-airshipctl-upload-git-mirror
|
||||||
|
- airship-airshipctl-update-github-issues
|
||||||
|
83
zuul.d/scripts/update_github_issues.py
Executable file
83
zuul.d/scripts/update_github_issues.py
Executable file
@ -0,0 +1,83 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import github
|
||||||
|
|
||||||
|
GH_USER = sys.argv[1]
|
||||||
|
GH_PW = sys.argv[2]
|
||||||
|
ZUUL_MESSAGE = sys.argv[3]
|
||||||
|
GERRIT_URL = sys.argv[4]
|
||||||
|
REPO_NAME = 'airshipit/airshipctl'
|
||||||
|
PROCESS_LABELS = ['wip', 'ready for review', 'triage', 'blocked']
|
||||||
|
|
||||||
|
|
||||||
|
def construct_issue_list(match_list: list) -> set:
|
||||||
|
new_list = []
|
||||||
|
for _issue in match_list:
|
||||||
|
try:
|
||||||
|
new_list.append(int(_issue))
|
||||||
|
except ValueError:
|
||||||
|
logging.warning(f'Value {_issue} could not be converted to `int` type')
|
||||||
|
return set(new_list)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_issue_number(commit_msg: str) -> dict:
|
||||||
|
# Searches for Relates-To or Closes tags first to match and return
|
||||||
|
logging.debug(f'Parsing commit message: {commit_msg}')
|
||||||
|
related = re.findall(r'(?<=Relates-To: #)([0-9]+?)(?=\n)', commit_msg)
|
||||||
|
logging.debug(f'Captured related issues: {related}')
|
||||||
|
closes = re.findall(r'(?<=Closes: #)([0-9]+?)(?=\n)', commit_msg)
|
||||||
|
logging.debug(f'Captured closes issues: {closes}')
|
||||||
|
if related or closes:
|
||||||
|
return {
|
||||||
|
'related': construct_issue_list(related),
|
||||||
|
'closes': construct_issue_list(closes)
|
||||||
|
}
|
||||||
|
# If no Relates-To or Closes tags are defined, find legacy [#X] style tags
|
||||||
|
logging.debug('Falling back to legacy tags')
|
||||||
|
legacy_matches = re.findall(r'(?<=\[#)([0-9]+?)(?=\])', commit_msg)
|
||||||
|
logging.debug(f'Captured legacy issues: {legacy_matches}')
|
||||||
|
if not legacy_matches:
|
||||||
|
return {}
|
||||||
|
return {
|
||||||
|
'related': construct_issue_list(legacy_matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def remove_duplicated_issue_numbers(issue_dict: dict) -> dict:
|
||||||
|
if 'closes' in issue_dict:
|
||||||
|
issue_dict['related'] = [x for x in issue_dict.get('related', []) if x not in issue_dict['closes']]
|
||||||
|
return issue_dict
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
issue_number_dict = parse_issue_number(ZUUL_MESSAGE)
|
||||||
|
issue_number_dict = remove_duplicated_issue_numbers(issue_number_dict)
|
||||||
|
gh = github.Github(GH_USER, GH_PW)
|
||||||
|
repo = gh.get_repo(REPO_NAME)
|
||||||
|
for key, issue_list in issue_number_dict.items():
|
||||||
|
for issue_number in issue_list:
|
||||||
|
issue = repo.get_issue(number=issue_number)
|
||||||
|
comment_msg = ''
|
||||||
|
link_exists = False
|
||||||
|
if key == 'closes':
|
||||||
|
issue.create_comment(f'The [Change]({GERRIT_URL}) that closes this issue was merged.')
|
||||||
|
for label in PROCESS_LABELS:
|
||||||
|
try:
|
||||||
|
issue.remove_from_labels(label)
|
||||||
|
except github.GithubException:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
issue.create_comment(f'A [Related Change]({GERRIT_URL} was merged. This issue may be ready to close.')
|
@ -58,6 +58,22 @@
|
|||||||
uPzQ1Ero9vGyHmFuvFczZK+TnJBxyKiyWr4kR9GbI3WVXMSa78M+kRqQmcnqdwS9AAFC2
|
uPzQ1Ero9vGyHmFuvFczZK+TnJBxyKiyWr4kR9GbI3WVXMSa78M+kRqQmcnqdwS9AAFC2
|
||||||
595F3m2UtgR6QKN5xbJJmWp7ipihdRvQ1eVl5GCjG7MBi27YvILp4cIWg+MO1I=
|
595F3m2UtgR6QKN5xbJJmWp7ipihdRvQ1eVl5GCjG7MBi27YvILp4cIWg+MO1I=
|
||||||
|
|
||||||
|
- secret:
|
||||||
|
name: airship-airshipctl-airshipit-github-username-password
|
||||||
|
data:
|
||||||
|
username: airshipbot
|
||||||
|
password: !encrypted/pkcs1-oaep
|
||||||
|
- AbUjw8rBEhFCVxOE/9dpdR4g+viQfC2/W0uewRWOU4duEZL5LXzCSZBLKaMFE1Oi38lut
|
||||||
|
PFyfPS2WqABWDgdYAHmYdgnxDqF/TXHPObQxqGwIJ9wxG3siplMXv6T6I0iz6/U7MfX7q
|
||||||
|
5D/jy9RWd+px7fvohbjG5rwL3wfZZsmn6KMrEzYbScHH7w8qYL6vnQr5Z0YRXs9h79VJ7
|
||||||
|
01XrtdipuFWYWILmwJzV25YZ2AavNFnk0p2a9zfDxYty+bFpkqKWrd92mgpsGIbckFS24
|
||||||
|
Wdhn/2gIfPv9/clBzUgTeK6v7TR1MpQDIQ6NWeF8YpB9Rm7fdmDbTQKXOwX0ung2L0+rk
|
||||||
|
GO8j9xzVNV+CsGgIKyOPEeOiloxEmDD7ie2CSp8pWnlb6nP6g+R2koOz0Xs/uvPO4ACS/
|
||||||
|
vARWor3q6zOKj7maW0Z2jZR+i/yGu2Pf+sJZt2HfvLMvYX2avP+9mtoyZY30cHBMSahZ+
|
||||||
|
pqpk7Oq6RVA63PPFHGAEhyD6c6tas0bC2/KHjjgLvcgxuzRVHcKJUTDW8Usmm2QTBijHn
|
||||||
|
mTMWfj2ffriZ4+ZtPmGDzGoAhoUe6oU8DI86opjGmDFcNk+2T8WEgJ7guvG57GzKXFnTd
|
||||||
|
zY8AzTMSMOKEzSaiiT2lvzBMFhSNRIBTM+m8I+DDBooy0nM4ijcHSP7MdOhGbs=
|
||||||
|
|
||||||
- secret:
|
- secret:
|
||||||
name: airshipctl-image-repo-credentials
|
name: airshipctl-image-repo-credentials
|
||||||
data:
|
data:
|
||||||
|
Loading…
Reference in New Issue
Block a user