Skip to content

Commit bcf764f

Browse files
authored
ci: add more details to PR comment about build and tests (#1054)
1 parent 5173c3f commit bcf764f

File tree

6 files changed

+162
-52
lines changed

6 files changed

+162
-52
lines changed

.github/actions/build_ya/action.yml

+28-3
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,19 @@ runs:
2828
- name: Init
2929
id: init
3030
shell: bash
31+
env:
32+
build_preset: ${{ inputs.build_preset }}
3133
run: |
3234
echo "SHELLOPTS=xtrace" >> $GITHUB_ENV
3335
export TMP_DIR=$(pwd)/tmp_build
3436
echo "TMP_DIR=$TMP_DIR" >> $GITHUB_ENV
3537
rm -rf $TMP_DIR && mkdir $TMP_DIR
36-
38+
39+
echo "BUILD_PRESET=$build_preset" >> $GITHUB_ENV
40+
echo "GITHUB_TOKEN=${{ github.token }}" >> $GITHUB_ENV
41+
3742
- name: build
43+
id: build
3844
shell: bash
3945
run: |
4046
extra_params=()
@@ -85,22 +91,41 @@ runs:
8591
echo "::debug::get version"
8692
./ya --version
8793
94+
echo "Build **{platform_name}-${BUILD_PRESET}** is running..." | .github/scripts/tests/comment-pr.py
95+
96+
# to be sure
97+
set -o pipefail
98+
8899
./ya make -k --build "${build_type}" --force-build-depends -D'BUILD_LANGUAGES=CPP PY3 PY2 GO' -T --stat -DCONSISTENT_DEBUG \
89100
--log-file "$TMP_DIR/ya_log.txt" --evlog-file "$TMP_DIR/ya_evlog.jsonl" \
90101
--cache-size 512G --link-threads "${{ inputs.link_threads }}" \
91-
"${extra_params[@]}" || (
102+
"${extra_params[@]}" |& tee $TMP_DIR/ya_make.log || (
92103
RC=$?
93104
echo "::debug::ya make RC=$RC"
105+
echo "status=failed" >> $GITHUB_OUTPUT
94106
)
95107
96108
- name: sync logs to s3
97109
if: always()
98110
shell: bash
99111
run: |
100112
echo "::group::s3-sync"
101-
s3cmd sync --acl-private --no-progress --stats --no-check-md5 "$TMP_DIR/" "$S3_BUCKET_PATH/build_logs/"
113+
s3cmd sync --acl-private --exclude="ya_make.log" --no-progress --stats --no-check-md5 "$TMP_DIR/" "$S3_BUCKET_PATH/build_logs/"
114+
s3cmd sync --acl-public --no-progress --stats --no-check-md5 "$TMP_DIR/ya_make.log" "$S3_BUCKET_PATH/build_logs/"
102115
echo "::endgroup::"
103116
117+
- name: comment-build-status
118+
if: github.event_name == 'pull_request' || github.event_name == 'pull_request_target'
119+
shell: bash
120+
run: |
121+
log_url="$S3_URL_PREFIX/build_logs/ya_make.log"
122+
123+
if [ "${{ steps.build.outputs.status }}" == "failed" ]; then
124+
echo "Build failed. see the [build logs]($log_url)." | .github/scripts/tests/comment-pr.py --fail
125+
else
126+
echo "Build successful." | .github/scripts/tests/comment-pr.py --ok
127+
fi
128+
104129
- name: show free space
105130
if: always()
106131
shell: bash

.github/actions/test_ya/action.yml

+8-9
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ runs:
6666
echo "TESTMO_TOKEN=${{ inputs.testman_token }}" >> $GITHUB_ENV
6767
echo "TESTMO_URL=${{ inputs.testman_url }}" >> $GITHUB_ENV
6868
echo "SUMMARY_LINKS=$(mktemp)" >> $GITHUB_ENV
69+
echo "GITHUB_TOKEN=${{ github.token }}" >> $GITHUB_ENV
70+
echo "BUILD_PRESET=${{ inputs.build_preset }}" >> $GITHUB_ENV
6971
7072
- name: prepare
7173
shell: bash
@@ -93,7 +95,6 @@ runs:
9395
BRANCH_TAG="$GITHUB_REF_NAME"
9496
ARCH="${{ runner.arch == 'X64' && 'x86-64' || runner.arch == 'ARM64' && 'arm64' || 'unknown' }}"
9597
96-
BUILD_PRESET="${{ inputs.build_preset }}"
9798
case "$BUILD_PRESET" in
9899
relwithdebinfo)
99100
TESTMO_SOURCE="ya-${ARCH}"
@@ -105,7 +106,7 @@ runs:
105106
TESTMO_SOURCE="ya-${ARCH}-${BUILD_PRESET/release-/}"
106107
;;
107108
*)
108-
echo "Invalid preset: ${{ inputs.build_preset }}"
109+
echo "Invalid preset: $BUILD_PRESET"
109110
exit 1
110111
;;
111112
esac
@@ -170,7 +171,7 @@ runs:
170171
)
171172
172173
# FIXME: copy-paste from build_ya
173-
case "${{ inputs.build_preset }}" in
174+
case "$BUILD_PRESET" in
174175
debug)
175176
params+=(--build "debug")
176177
;;
@@ -196,7 +197,7 @@ runs:
196197
)
197198
;;
198199
*)
199-
echo "Invalid preset: ${{ inputs.build_preset }}"
200+
echo "Invalid preset: $BUILD_PRESET"
200201
exit 1
201202
;;
202203
esac
@@ -213,6 +214,8 @@ runs:
213214
echo "::debug::get version"
214215
./ya --version
215216
217+
echo "Tests are running..." | .github/scripts/tests/comment-pr.py
218+
216219
if [ ! -z "${{ inputs.bazel_remote_username }}" ]; then
217220
echo "::debug::start tests"
218221
@@ -300,20 +303,16 @@ runs:
300303
- name: write tests summary
301304
shell: bash
302305
if: always()
303-
env:
304-
GITHUB_TOKEN: ${{ github.token }}
305306
run: |
306307
mkdir $ARTIFACTS_DIR/summary/
307308
308309
cat $SUMMARY_LINKS | python3 -c 'import sys; print(" | ".join([v for _, v in sorted([l.strip().split(" ", 1) for l in sys.stdin], key=lambda a: (int(a[0]), a))]))' >> $GITHUB_STEP_SUMMARY
309310
310-
platform_name=$(uname | tr '[:upper:]' '[:lower:]')-$(arch)
311-
312311
.github/scripts/tests/generate-summary.py \
313312
--summary-out-path $ARTIFACTS_DIR/summary/ \
314313
--summary-url-prefix $S3_URL_PREFIX/summary/ \
315314
--test-history-url $TEST_HISTORY_URL \
316-
--build-preset "${platform_name}-${{ inputs.build_preset }}" \
315+
--build-preset "$BUILD_PRESET" \
317316
"Tests" ya-test.html "$JUNIT_REPORT_XML"
318317
319318
- name: sync test results to s3

.github/scripts/tests/comment-pr.py

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/usr/bin/env python
2+
import os
3+
import json
4+
import argparse
5+
from github import Github, Auth as GithubAuth
6+
from github.PullRequest import PullRequest
7+
from gh_status import update_pr_comment_text
8+
9+
10+
def main():
11+
parser = argparse.ArgumentParser()
12+
parser.add_argument("--rewrite", dest="rewrite", action="store_true")
13+
parser.add_argument("--color", dest="color", default="white")
14+
parser.add_argument("--fail", dest="fail", action="store_true")
15+
parser.add_argument("--ok", dest="ok", action="store_true")
16+
parser.add_argument("text", type=argparse.FileType("r"), nargs="?", default="-")
17+
18+
args = parser.parse_args()
19+
color = args.color
20+
21+
if args.ok:
22+
color = 'green'
23+
elif args.fail:
24+
color = 'red'
25+
26+
build_preset = os.environ["BUILD_PRESET"]
27+
28+
gh = Github(auth=GithubAuth.Token(os.environ["GITHUB_TOKEN"]))
29+
30+
with open(os.environ["GITHUB_EVENT_PATH"]) as fp:
31+
event = json.load(fp)
32+
33+
pr = gh.create_from_raw_data(PullRequest, event["pull_request"])
34+
35+
update_pr_comment_text(pr, build_preset, color, args.text.read().rstrip(), args.rewrite)
36+
37+
38+
if __name__ == "__main__":
39+
main()

.github/scripts/tests/generate-summary.py

+19-38
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/env python3
22
import argparse
33
import dataclasses
4+
import datetime
45
import os
56
import re
67
import json
@@ -12,6 +13,7 @@
1213
from typing import List, Optional, Dict
1314
from jinja2 import Environment, FileSystemLoader, StrictUndefined
1415
from junit_utils import get_property_value, iter_xml_files
16+
from gh_status import update_pr_comment_text
1517

1618

1719
class TestStatus(Enum):
@@ -155,7 +157,7 @@ def render(self, add_footnote=False):
155157
github_srv = os.environ.get("GITHUB_SERVER_URL", "https://github.com")
156158
repo = os.environ.get("GITHUB_REPOSITORY", "ydb-platform/ydb")
157159

158-
footnote_url = f"{github_srv}/{repo}/tree/main/.github/config"
160+
footnote_url = f"{github_srv}/{repo}/tree/main/.github/config/muted_ya.txt"
159161

160162
footnote = "[^1]" if add_footnote else f'<sup>[?]({footnote_url} "All mute rules are defined here")</sup>'
161163

@@ -287,18 +289,20 @@ def gen_summary(summary_url_prefix, summary_out_folder, paths):
287289
return summary
288290

289291

290-
def get_comment_text(pr: PullRequest, summary: TestSummary, build_preset: str, test_history_url: str):
292+
def get_comment_text(pr: PullRequest, summary: TestSummary, test_history_url: str):
291293
if summary.is_empty:
292294
return [
293-
f":red_circle: **{build_preset}**: Test run completed, no test results found for commit {pr.head.sha}. "
295+
f"Test run completed, no test results found for commit {pr.head.sha}. "
294296
f"Please check build logs."
295297
]
296298
elif summary.is_failed:
297-
result = f":red_circle: **{build_preset}**: some tests FAILED"
299+
result = f"Some tests failed, follow the links below."
298300
else:
299-
result = f":green_circle: **{build_preset}**: all tests PASSED"
301+
result = f"Tests successful."
300302

301-
body = [f"{result} for commit {pr.head.sha}."]
303+
body = [
304+
result
305+
]
302306

303307
if test_history_url:
304308
body.append("")
@@ -309,36 +313,6 @@ def get_comment_text(pr: PullRequest, summary: TestSummary, build_preset: str, t
309313
return body
310314

311315

312-
def update_pr_comment(run_number: int, pr: PullRequest, summary: TestSummary, build_preset: str, test_history_url: str):
313-
header = f"<!-- status pr={pr.number}, run={{}} -->"
314-
header_re = re.compile(header.format(r"(\d+)"))
315-
316-
comment = body = None
317-
318-
for c in pr.get_issue_comments():
319-
if matches := header_re.match(c.body):
320-
comment = c
321-
if int(matches[1]) == run_number:
322-
body = [c.body, "", "---", ""]
323-
324-
if body is None:
325-
body = [
326-
header.format(run_number),
327-
"> [!NOTE]",
328-
"> This is an automated comment that will be appended during run.",
329-
"",
330-
]
331-
332-
body.extend(get_comment_text(pr, summary, build_preset, test_history_url))
333-
334-
body = "\n".join(body)
335-
336-
if comment is None:
337-
pr.create_issue_comment(body)
338-
else:
339-
comment.edit(body)
340-
341-
342316
def main():
343317
parser = argparse.ArgumentParser()
344318
parser.add_argument("--summary-out-path", required=True)
@@ -364,9 +338,16 @@ def main():
364338
with open(os.environ["GITHUB_EVENT_PATH"]) as fp:
365339
event = json.load(fp)
366340

367-
run_number = int(os.environ.get("GITHUB_RUN_NUMBER"))
368341
pr = gh.create_from_raw_data(PullRequest, event["pull_request"])
369-
update_pr_comment(run_number, pr, summary, args.build_preset, args.test_history_url)
342+
343+
text = get_comment_text(pr, summary, args.test_history_url)
344+
345+
if summary.is_empty | summary.is_failed:
346+
color = 'red'
347+
else:
348+
color = 'green'
349+
350+
update_pr_comment_text(pr, args.build_preset, color, text='\n'.join(text), rewrite=False)
370351

371352

372353
if __name__ == "__main__":

.github/scripts/tests/gh_status.py

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import datetime
2+
import platform
3+
from github.PullRequest import PullRequest
4+
5+
6+
def get_timestamp():
7+
return datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
8+
9+
10+
def get_platform_name():
11+
return f'{platform.system().lower()}-{platform.machine()}'
12+
13+
14+
def update_pr_comment_text(pr: PullRequest, build_preset: str, color: str, text: str, rewrite: bool):
15+
platform_name = get_platform_name()
16+
header = f"<!-- status pr={pr.number}, preset={platform_name}-{build_preset} -->"
17+
18+
body = comment = None
19+
for c in pr.get_issue_comments():
20+
if c.body.startswith(header):
21+
print(f"found comment id={c.id}")
22+
comment = c
23+
if not rewrite:
24+
body = [c.body]
25+
break
26+
27+
if body is None:
28+
body = [header]
29+
30+
indicator = f":{color}_circle:"
31+
body.append(f"{indicator} `{get_timestamp()}` {text}")
32+
33+
body = "\n".join(body)
34+
35+
if '{platform_name}' in body:
36+
# input can contain '{platform_name}'
37+
body = body.replace('{platform_name}', platform_name)
38+
39+
if comment is None:
40+
print(f"post new comment")
41+
pr.create_issue_comment(body)
42+
else:
43+
print(f"edit comment")
44+
comment.edit(body)

.github/workflows/build_and_test_ya.yml

+24-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ on:
4949
put_build_results_to_cache:
5050
type: boolean
5151
default: true
52-
52+
defaults:
53+
run:
54+
shell: bash
5355
jobs:
5456
main:
5557
name: Build and test ${{ inputs.build_preset }}
@@ -63,7 +65,20 @@ jobs:
6365
- name: Checkout
6466
uses: actions/checkout@v3
6567
if: github.event.pull_request.head.sha == ''
66-
68+
69+
- name: comment-build-start
70+
if: github.event_name == 'pull_request' || github.event_name == 'pull_request_target'
71+
shell: bash
72+
env:
73+
BUILD_PRESET: ${{ inputs.build_preset }}
74+
GITHUB_TOKEN: ${{ github.token }}
75+
run: |
76+
jobs_url="https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/jobs"
77+
# tricky: we are searching job with name that contains build_preset
78+
check_url=$(curl -s $jobs_url | jq --arg n "$BUILD_PRESET" -r '.jobs[] | select(.name | contains($n)) | .html_url')
79+
80+
echo "Pre-commit [check]($check_url) for ${{ github.event.pull_request.head.sha }} has started." | .github/scripts/tests/comment-pr.py --rewrite
81+
6782
- name: Prepare s3cmd
6883
uses: ./.github/actions/s3cmd
6984
with:
@@ -101,3 +116,10 @@ jobs:
101116
bazel_remote_password: ${{ inputs.put_build_results_to_cache && secrets.REMOTE_CACHE_PASSWORD || '' }}
102117
link_threads: ${{ inputs.link_threads }}
103118
test_threads: ${{ inputs.test_threads }}
119+
120+
- name: comment-if-cancel
121+
if: cancelled() && (github.event_name == 'pull_request' || github.event_name == 'pull_request_target')
122+
env:
123+
BUILD_PRESET: ${{ inputs.build_preset }}
124+
GITHUB_TOKEN: ${{ github.token }}
125+
run: echo "Check cancelled" | .github/scripts/tests/comment-pr.py --color black

0 commit comments

Comments
 (0)