Skip to content

Commit 797c546

Browse files
authored
Trigger workflow move github api cod to github.py (#746)
1 parent 96bfd28 commit 797c546

File tree

3 files changed

+67
-62
lines changed

3 files changed

+67
-62
lines changed

.github/workflows/cpp-packaging.yml

+1
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,7 @@ jobs:
782782
- name: Use GitHub API to start workflow
783783
shell: bash
784784
run: |
785+
pip install -r scripts/gha/requirements.txt
785786
if [[ -z ${USE_EXPANDED_MATRIX} ]]; then
786787
USE_EXPANDED_MATRIX=0
787788
fi

scripts/gha/github.py

+50-19
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import requests
2222
import json
2323
import shutil
24+
import re
2425

2526
from absl import logging
2627
from requests.adapters import HTTPAdapter
@@ -35,9 +36,24 @@
3536
REPO = 'firebase-cpp-sdk'
3637

3738
BASE_URL = 'https://api.github.com'
38-
FIREBASE_URL = '%s/repos/%s/%s' % (BASE_URL, OWNER, REPO)
39+
GITHUB_API_URL = '%s/repos/%s/%s' % (BASE_URL, OWNER, REPO)
3940
logging.set_verbosity(logging.INFO)
4041

42+
43+
def set_repo_url(repo):
44+
match = re.match(r'https://github\.com/([^/]+)/([^/.]+)', repo)
45+
if not match:
46+
logging.info('Error, only pattern https://github.com/\{repo_owner\}/\{repo_name\} are allowed.')
47+
return False
48+
49+
(repo_owner, repo_name) = match.groups()
50+
global OWNER, REPO, GITHUB_API_URL
51+
OWNER = repo_owner
52+
REPO = repo_name
53+
GITHUB_API_URL = '%s/repos/%s/%s' % (BASE_URL, OWNER, REPO)
54+
return True
55+
56+
4157
def requests_retry_session(retries=RETRIES,
4258
backoff_factor=BACKOFF,
4359
status_forcelist=RETRY_STATUS):
@@ -54,7 +70,7 @@ def requests_retry_session(retries=RETRIES,
5470

5571
def create_issue(token, title, label, body):
5672
"""Create an issue: https://docs.github.com/en/rest/reference/issues#create-an-issue"""
57-
url = f'{FIREBASE_URL}/issues'
73+
url = f'{GITHUB_API_URL}/issues'
5874
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
5975
data = {'title': title, 'labels': [label], 'body': body}
6076
with requests.post(url, headers=headers, data=json.dumps(data), timeout=TIMEOUT) as response:
@@ -64,7 +80,7 @@ def create_issue(token, title, label, body):
6480

6581
def get_issue_body(token, issue_number):
6682
"""https://docs.github.com/en/rest/reference/issues#get-an-issue-comment"""
67-
url = f'{FIREBASE_URL}/issues/{issue_number}'
83+
url = f'{GITHUB_API_URL}/issues/{issue_number}'
6884
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
6985
with requests_retry_session().get(url, headers=headers, timeout=TIMEOUT) as response:
7086
logging.info("get_issue_body: %s response: %s", url, response)
@@ -73,7 +89,7 @@ def get_issue_body(token, issue_number):
7389

7490
def update_issue(token, issue_number, data):
7591
"""Update an issue: https://docs.github.com/en/rest/reference/issues#update-an-issue"""
76-
url = f'{FIREBASE_URL}/issues/{issue_number}'
92+
url = f'{GITHUB_API_URL}/issues/{issue_number}'
7793
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
7894
with requests_retry_session().patch(url, headers=headers, data=json.dumps(data), timeout=TIMEOUT) as response:
7995
logging.info("update_issue: %s response: %s", url, response)
@@ -102,7 +118,7 @@ def search_issues_by_label(label):
102118

103119
def list_comments(token, issue_number):
104120
"""https://docs.github.com/en/rest/reference/issues#list-issue-comments"""
105-
url = f'{FIREBASE_URL}/issues/{issue_number}/comments'
121+
url = f'{GITHUB_API_URL}/issues/{issue_number}/comments'
106122
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
107123
with requests_retry_session().get(url, headers=headers, timeout=TIMEOUT) as response:
108124
logging.info("list_comments: %s response: %s", url, response)
@@ -111,7 +127,7 @@ def list_comments(token, issue_number):
111127

112128
def add_comment(token, issue_number, comment):
113129
"""https://docs.github.com/en/rest/reference/issues#create-an-issue-comment"""
114-
url = f'{FIREBASE_URL}/issues/{issue_number}/comments'
130+
url = f'{GITHUB_API_URL}/issues/{issue_number}/comments'
115131
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
116132
data = {'body': comment}
117133
with requests.post(url, headers=headers, data=json.dumps(data), timeout=TIMEOUT) as response:
@@ -120,7 +136,7 @@ def add_comment(token, issue_number, comment):
120136

121137
def update_comment(token, comment_id, comment):
122138
"""https://docs.github.com/en/rest/reference/issues#update-an-issue-comment"""
123-
url = f'{FIREBASE_URL}/issues/comments/{comment_id}'
139+
url = f'{GITHUB_API_URL}/issues/comments/{comment_id}'
124140
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
125141
data = {'body': comment}
126142
with requests_retry_session().patch(url, headers=headers, data=json.dumps(data), timeout=TIMEOUT) as response:
@@ -129,15 +145,15 @@ def update_comment(token, comment_id, comment):
129145

130146
def delete_comment(token, comment_id):
131147
"""https://docs.github.com/en/rest/reference/issues#delete-an-issue-comment"""
132-
url = f'{FIREBASE_URL}/issues/comments/{comment_id}'
148+
url = f'{GITHUB_API_URL}/issues/comments/{comment_id}'
133149
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
134150
with requests.delete(url, headers=headers, timeout=TIMEOUT) as response:
135151
logging.info("delete_comment: %s response: %s", url, response)
136152

137153

138154
def add_label(token, issue_number, label):
139155
"""https://docs.github.com/en/rest/reference/issues#add-labels-to-an-issue"""
140-
url = f'{FIREBASE_URL}/issues/{issue_number}/labels'
156+
url = f'{GITHUB_API_URL}/issues/{issue_number}/labels'
141157
headers={}
142158
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
143159
data = [label]
@@ -147,15 +163,15 @@ def add_label(token, issue_number, label):
147163

148164
def delete_label(token, issue_number, label):
149165
"""https://docs.github.com/en/rest/reference/issues#delete-a-label"""
150-
url = f'{FIREBASE_URL}/issues/{issue_number}/labels/{label}'
166+
url = f'{GITHUB_API_URL}/issues/{issue_number}/labels/{label}'
151167
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
152168
with requests.delete(url, headers=headers, timeout=TIMEOUT) as response:
153169
logging.info("delete_label: %s response: %s", url, response)
154170

155171

156172
def list_artifacts(token, run_id):
157173
"""https://docs.github.com/en/rest/reference/actions#list-workflow-run-artifacts"""
158-
url = f'{FIREBASE_URL}/actions/runs/{run_id}/artifacts'
174+
url = f'{GITHUB_API_URL}/actions/runs/{run_id}/artifacts'
159175
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
160176
with requests_retry_session().get(url, headers=headers, timeout=TIMEOUT) as response:
161177
logging.info("list_artifacts: %s response: %s", url, response)
@@ -164,7 +180,7 @@ def list_artifacts(token, run_id):
164180

165181
def download_artifact(token, artifact_id, output_path):
166182
"""https://docs.github.com/en/rest/reference/actions#download-an-artifact"""
167-
url = f'{FIREBASE_URL}/actions/artifacts/{artifact_id}/zip'
183+
url = f'{GITHUB_API_URL}/actions/artifacts/{artifact_id}/zip'
168184
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
169185
with requests.get(url, headers=headers, stream=True, timeout=TIMEOUT) as response:
170186
logging.info("download_artifact: %s response: %s", url, response)
@@ -174,17 +190,18 @@ def download_artifact(token, artifact_id, output_path):
174190

175191
def dismiss_review(token, pull_number, review_id, message):
176192
"""https://docs.github.com/en/rest/reference/pulls#dismiss-a-review-for-a-pull-request"""
177-
url = f'{FIREBASE_URL}/pulls/{pull_number}/reviews/{review_id}/dismissals'
193+
url = f'{GITHUB_API_URL}/pulls/{pull_number}/reviews/{review_id}/dismissals'
178194
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
179195
data = {'message': message}
180196
with requests_retry_session().put(url, headers=headers, data=json.dumps(data),
181197
stream=True, timeout=TIMEOUT) as response:
182198
logging.info("dismiss_review: %s response: %s", url, response)
183199
return response.json()
184200

201+
185202
def get_reviews(token, pull_number):
186203
"""https://docs.github.com/en/rest/reference/pulls#list-reviews-for-a-pull-request"""
187-
url = f'{FIREBASE_URL}/pulls/{pull_number}/reviews'
204+
url = f'{GITHUB_API_URL}/pulls/{pull_number}/reviews'
188205
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
189206
page = 1
190207
per_page = 100
@@ -203,19 +220,32 @@ def get_reviews(token, pull_number):
203220
return results
204221

205222

206-
def workflow_dispatch(token, workflow_id, ref, inputs):
223+
def create_workflow_dispatch(token, workflow_id, ref, inputs):
207224
"""https://docs.github.com/en/rest/reference/actions#create-a-workflow-dispatch-event"""
208-
url = f'{FIREBASE_URL}/actions/workflows/{workflow_id}/dispatches'
225+
url = f'{GITHUB_API_URL}/actions/workflows/{workflow_id}/dispatches'
209226
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
210227
data = {'ref': ref, 'inputs': inputs}
211228
with requests.post(url, headers=headers, data=json.dumps(data),
212229
stream=True, timeout=TIMEOUT) as response:
213-
logging.info("workflow_dispatch: %s response: %s", url, response)
230+
logging.info("create_workflow_dispatch: %s response: %s", url, response)
231+
# Response Status: 204 No Content
232+
return True if response.status_code == 204 else False
233+
234+
235+
def list_workflows(token, workflow_id, branch):
236+
"""https://docs.github.com/en/rest/reference/actions#list-workflow-runs-for-a-repository"""
237+
url = f'{GITHUB_API_URL}/actions/workflows/{workflow_id}/runs'
238+
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
239+
data = {'event': 'workflow_dispatch', 'branch': branch}
240+
with requests.get(url, headers=headers, data=json.dumps(data),
241+
stream=True, timeout=TIMEOUT) as response:
242+
logging.info("list_workflows: %s response: %s", url, response)
243+
return response.json()
214244

215245

216246
def create_pull_request(token, head, base, title, body, maintainer_can_modify):
217247
"""https://docs.github.com/en/rest/reference/pulls#create-a-pull-request"""
218-
url = f'{FIREBASE_URL}/pulls'
248+
url = f'{GITHUB_API_URL}/pulls'
219249
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
220250
data = {'head': head, 'base': base, 'title': title, 'body': body,
221251
'maintainer_can_modify': maintainer_can_modify}
@@ -224,9 +254,10 @@ def create_pull_request(token, head, base, title, body, maintainer_can_modify):
224254
logging.info("create_pull_request: %s response: %s", head, response)
225255
return True if response.status_code == 201 else False
226256

257+
227258
def list_pull_requests(token, state, head, base):
228259
"""https://docs.github.com/en/rest/reference/pulls#list-pull-requests"""
229-
url = f'{FIREBASE_URL}/pulls'
260+
url = f'{GITHUB_API_URL}/pulls'
230261
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
231262
page = 1
232263
per_page = 100

scripts/gha/trigger_workflow.py

+16-43
Original file line numberDiff line numberDiff line change
@@ -29,70 +29,43 @@
2929
"""
3030

3131
import argparse
32-
import json
33-
import os
34-
import re
3532
import subprocess
3633
import time
3734
import urllib.parse
35+
import github
3836

3937
def main():
4038
args = parse_cmdline_args()
41-
if args.repo is None:
42-
args.repo=subprocess.check_output(['git', 'config', '--get', 'remote.origin.url']).decode('utf-8').rstrip('\n').lower()
43-
print('autodetected repo: %s' % args.repo)
4439
if args.branch is None:
45-
args.branch=subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).decode('utf-8').rstrip('\n')
46-
print('autodetected branch: %s' % args.branch)
47-
if not args.repo.startswith('https://github.com/'):
48-
print('Error, only https://github.com/ repositories are allowed.')
40+
args.branch=subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).decode('utf-8').rstrip('\n')
41+
print('autodetected branch: %s' % args.branch)
42+
if args.repo: # else use default firebase/firebase-cpp-sdk repo
43+
if not github.set_repo_url(args.repo):
4944
exit(2)
50-
(repo_owner, repo_name) = re.match(r'https://github\.com/([^/]+)/([^/.]+)', args.repo).groups()
45+
else:
46+
print('set repo url to: %s' % github.GITHUB_API_URL)
5147

52-
# POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches
53-
request_url = 'https://api.github.com/repos/%s/%s/actions/workflows/%s/dispatches' % (repo_owner, repo_name, args.workflow)
5448
json_params = {}
5549
for param in args.param:
56-
json_params[param[0]] = param[1]
57-
json_text = '{"ref":%s,"inputs":%s}' % (json.dumps(args.branch), json.dumps(json_params))
50+
json_params[param[0]] = param[1]
5851
if args.verbose or args.dryrun:
59-
print('request_url: %s' % request_url)
60-
print('request_body: %s' % json_text)
52+
print(f'request_url: {github.GITHUB_API_URL}/actions/workflows/{args.workflow}/dispatches')
53+
print(f'request_body: ref: {args.branch}, inputs: {json_params}')
6154
if args.dryrun:
6255
return(0)
6356

6457
print('Sending request to GitHub API...')
65-
run_output = subprocess.check_output([args.curl,
66-
'-s', '-o', '-', '-w', '\nHTTP status %{http_code}\n',
67-
'-X', 'POST',
68-
'-H', 'Accept: application/vnd.github.v3+json',
69-
'-H', 'Authorization: token %s' % args.token,
70-
request_url, '-d', json_text]
71-
+ ([] if not args.verbose else ['-v'])).decode('utf-8').rstrip('\n')
72-
if args.verbose:
73-
print(run_output)
74-
if not re.search('HTTP status 2[0-9][0-9]$', run_output):
75-
if not args.verbose:
76-
print(run_output)
77-
# Super quick and dirty way to get the message text since the appended status code means that
78-
# the contents are not valid JSON.
79-
error_message = re.search(r'"message": "([^"]+)"', run_output).group(1)
80-
print('%sFailed to trigger workflow %s: %s' % (
81-
'::error ::' if args.in_github_action else '', args.workflow, error_message))
58+
if not github.create_workflow_dispatch(args.token, args.workflow, args.branch, json_params):
59+
print('%sFailed to trigger workflow %s' % (
60+
'::error ::' if args.in_github_action else '', args.workflow))
8261
return(-1)
8362

8463
print('Success!')
8564
time.sleep(args.sleep) # Give a few seconds for the job to become queued.
8665
# Unfortunately, the GitHub REST API doesn't return the new workflow's run ID.
8766
# Query the list of workflows to find the one we just added.
88-
request_url = 'https://api.github.com/repos/%s/%s/actions/workflows/%s/runs?event=workflow_dispatch&branch=%s' % (repo_owner, repo_name, args.workflow, args.branch)
89-
run_output = subprocess.check_output([args.curl,
90-
'-s', '-X', 'GET',
91-
'-H', 'Accept: application/vnd.github.v3+json',
92-
'-H', 'Authorization: token %s' % args.token,
93-
request_url]).decode('utf-8').rstrip('\n')
67+
workflows = github.list_workflows(args.token, args.workflow, args.branch)
9468
run_id = 0
95-
workflows = json.loads(run_output)
9669
if "workflow_runs" in workflows:
9770
branch_sha = subprocess.check_output(['git', 'rev-parse', args.branch]).decode('utf-8').rstrip('\n')
9871
for workflow in workflows['workflow_runs']:
@@ -108,8 +81,8 @@ def main():
10881
workflow_url = 'https://github.com/firebase/firebase-cpp-sdk/actions/runs/%s' % (run_id)
10982
else:
11083
# Couldn't get a run ID, use a generic URL.
111-
workflow_url = 'https://github.com/%s/%s/actions/workflows/%s?query=%s+%s' % (
112-
repo_owner, repo_name, args.workflow,
84+
workflow_url = '/%s/actions/workflows/%s?query=%s+%s' % (
85+
github.GITHUB_API_URL, args.workflow,
11386
urllib.parse.quote('event:workflow_dispatch', safe=''),
11487
urllib.parse.quote('branch:'+args.branch, safe=''))
11588
print('%sStarted workflow %s: %s' % ('::warning ::' if args.in_github_action else '',

0 commit comments

Comments
 (0)