Skip to content

Commit a49d31c

Browse files
authored
Update to process rehearsal jobs and error if test failures and flag set (#142)
* Update to process rehearsal jobs and error if test failures and flag set * Update from review comments * Clean lint issues
1 parent f1dc2fb commit a49d31c

File tree

8 files changed

+96
-13
lines changed

8 files changed

+96
-13
lines changed

cli/objects/job.py

+39-8
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def __init__(
3535
build_id: Optional[str],
3636
gcs_bucket: str,
3737
firewatch_config: Configuration,
38+
pr_id: Optional[str] = "",
3839
) -> None:
3940
"""
4041
Constructs the Job object.
@@ -45,6 +46,7 @@ def __init__(
4546
build_id (Optional[str]): The build ID that needs to be reported. The value of $BUILD_ID
4647
gcs_bucket (str): The bucket that Prow job logs are stored
4748
firewatch_config (Configuration): The Configuration object.
49+
pr_ID (Optional[str]): The pull request number rehearsal job is running for. The value of $PULL_NUMBER
4850
"""
4951
self.logger = get_logger(__name__)
5052

@@ -56,6 +58,17 @@ def __init__(
5658
job_name=self.name,
5759
build_id=self.build_id,
5860
)
61+
if self.is_rehearsal:
62+
try:
63+
self.pr_id = pr_id or os.getenv("PULL_NUMBER") or self.name.split("-")[1] # type: ignore
64+
except IndexError:
65+
self.logger.warning(
66+
f"Pull number for job {self.name} not obtained, reporting may not be complete.",
67+
)
68+
self.pr_id = "1"
69+
self.logger.info(f"PR ID: {self.pr_id}")
70+
else:
71+
self.pr_id = ""
5972
self.firewatch_config = firewatch_config
6073

6174
# Set GCS bucket values
@@ -81,6 +94,7 @@ def __init__(
8194
job_name=self.name,
8295
build_id=self.build_id,
8396
job_name_safe=self.name_safe,
97+
pr_id=self.pr_id,
8498
)
8599
self.junit_dir = self._download_junit(
86100
downloads_directory=self.download_path,
@@ -89,6 +103,7 @@ def __init__(
89103
job_name=self.name,
90104
build_id=self.build_id,
91105
job_name_safe=self.name_safe,
106+
pr_id=self.pr_id,
92107
)
93108

94109
# Get a list of failures
@@ -134,6 +149,7 @@ def _download_junit(
134149
job_name: Optional[str],
135150
build_id: Optional[str],
136151
job_name_safe: Optional[str],
152+
pr_id: Optional[str],
137153
) -> str:
138154
"""
139155
Used to download any JUnit files found in the artifacts directory of a job.
@@ -145,6 +161,7 @@ def _download_junit(
145161
job_name (Optional[str]): The name of the job that artifacts should be downloaded for.
146162
build_id (Optional[str]): The build ID of the job that artifacts should be downloaded for.
147163
job_name_safe (Optional[str]): The safe job name of the job that artifacts should be downloaded for.
164+
pr_id (Optional[str]): The pull request number of the rehearsal job that artifacts should be downloaded for.
148165
149166
Returns:
150167
str: A string object representing the path that artifacts have been downloaded to.
@@ -156,10 +173,16 @@ def _download_junit(
156173
if not os.path.exists(path):
157174
os.mkdir(path)
158175

159-
blobs = storage_client.list_blobs(
160-
gcs_bucket,
161-
prefix=f"logs/{job_name}/{build_id}/artifacts/{job_name_safe}",
162-
)
176+
if self.is_rehearsal:
177+
blobs = storage_client.list_blobs(
178+
gcs_bucket,
179+
prefix=f"pr-logs/pull/openshift_release/{pr_id}/{job_name}/{build_id}/artifacts/{job_name_safe}",
180+
)
181+
else:
182+
blobs = storage_client.list_blobs(
183+
gcs_bucket,
184+
prefix=f"logs/{job_name}/{build_id}/artifacts/{job_name_safe}",
185+
)
163186

164187
for blob in blobs:
165188
blob_name = blob.name.split("/")[-1]
@@ -198,6 +221,7 @@ def _download_logs(
198221
job_name: Optional[str],
199222
build_id: Optional[str],
200223
job_name_safe: Optional[str],
224+
pr_id: Optional[str],
201225
) -> str:
202226
"""
203227
Used to download the logs of the job to be checked.
@@ -209,6 +233,7 @@ def _download_logs(
209233
job_name (Optional[str]): The name of the job that logs should be downloaded for.
210234
build_id (Optional[str]): The build ID of the job that logs should be downloaded for.
211235
job_name_safe (Optional[str]): The safe job name of the job that logs should be downloaded for.
236+
pr_id (Optional[str]): The pull request number for the rehearsal job that artifacts should be downloaded for.
212237
213238
Returns:
214239
str: A string object representing the path to the downloaded logs.
@@ -222,10 +247,16 @@ def _download_logs(
222247
if not os.path.exists(path):
223248
os.mkdir(path)
224249

225-
blobs = storage_client.list_blobs(
226-
gcs_bucket,
227-
prefix=f"logs/{job_name}/{build_id}/artifacts/{job_name_safe}",
228-
)
250+
if self.is_rehearsal:
251+
blobs = storage_client.list_blobs(
252+
gcs_bucket,
253+
prefix=f"pr-logs/pull/openshift_release/{pr_id}/{job_name}/{build_id}/artifacts/{job_name_safe}",
254+
)
255+
else:
256+
blobs = storage_client.list_blobs(
257+
gcs_bucket,
258+
prefix=f"logs/{job_name}/{build_id}/artifacts/{job_name_safe}",
259+
)
229260

230261
for blob in blobs:
231262
blob_name = blob.name.split("/")[-1]

cli/report/__init__.py

+8
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ def validate_verbose_test_failure_reporting_ticket_limit(
6363
required=False,
6464
type=click.STRING,
6565
)
66+
@click.option(
67+
"--pr-id",
68+
help="The pull request number that the rehearsal job is for. The value of $PULL_NUMBER",
69+
required=False,
70+
type=click.STRING,
71+
)
6672
@click.option(
6773
"--gcs-bucket",
6874
help="The name of the GCS bucket that holds OpenShift CI logs",
@@ -116,6 +122,7 @@ def report(
116122
job_name: str,
117123
job_name_safe: str,
118124
build_id: str,
125+
pr_id: str,
119126
gcs_bucket: str,
120127
firewatch_config_path: Optional[str],
121128
jira_config_path: str,
@@ -140,6 +147,7 @@ def report(
140147
build_id=build_id,
141148
gcs_bucket=gcs_bucket,
142149
firewatch_config=config,
150+
pr_id=pr_id,
143151
)
144152

145153
# Build the Report object and report issues to Jira

cli/report/report.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,20 @@ def __init__(self, firewatch_config: Configuration, job: Job) -> None:
4141
"""
4242
self.logger = get_logger(__name__)
4343

44-
# If job is a rehearsal, exit 0
44+
# If job is a rehearsal
4545
if job.is_rehearsal:
46-
exit(0)
46+
self.logger.info(f"Deleting job directory: {job.download_path}")
47+
try:
48+
shutil.rmtree(job.download_path)
49+
except Exception as error:
50+
self.logger.error(f"Error deleting job directory: {error}")
51+
if firewatch_config.fail_with_test_failures and job.has_test_failures:
52+
self.logger.info(
53+
"Test failures found and --fail-with-test-failures flag is set. Exiting with exit code 1",
54+
)
55+
exit(1)
56+
else:
57+
exit(0)
4758

4859
# If job has failures, file bugs
4960
if job.has_failures:

development/env.list

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ JIRA_SERVER_URL=
44

55
# Job Information
66
BUILD_ID=
7+
# PULL_NUMBER=
78
JOB_NAME_SAFE=
89
JOB_NAME=
910
# Firewatch Configuration

docs/cli_usage_guide.md

+3
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ Options:
6969
OpenShift CI logs
7070
--build-id TEXT The build ID that needs to be reported. The
7171
value of $BUILD_ID
72+
--pr-id TEXT The pull request number that rehearsal job is
73+
for. The value of $PULL_NUMBER
7274
--job-name-safe TEXT The safe name of a test in a Prow job. The
7375
value of $JOB_NAME_SAFE
7476
--job-name TEXT The full name of a Prow job. The value of
@@ -84,6 +86,7 @@ $ export BUILD_ID="some_build_id"
8486
$ export JOB_NAME_SAFE="some_safe_job_name"
8587
$ export JOB_NAME="some_job_name"
8688
$ export FIREWATCH_DEFAULT_JIRA_PROJECT="PROJECT"
89+
$ export PULL_NUMBER="some_pull_request_number"
8790
8891
# OPTIONAL DEFAULTS
8992
# $ export FIREWATCH_DEFAULT_JIRA_EPIC="PROJECT-123"

docs/contribution_guide.md

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ We strive to maintain a friendly and inclusive community. We have not yet establ
5858
export BUILD_ID=""
5959
export JOB_NAME_SAFE=""
6060
export JOB_NAME=""
61+
export PULL_NUMBER=""
6162
export FIREWATCH_CONFIG=""
6263
export FIREWATCH_DEFAULT_JIRA_PROJECT=""
6364
```
@@ -72,6 +73,7 @@ We strive to maintain a friendly and inclusive community. We have not yet establ
7273
- `JIRA_TOKEN`: The token needed to log in to the Jira service account that firewatch will use.
7374
- `JIRA_SERVER`: URL to Jira server you would like to test against (should be `https://issues.stage.redhat.com`)
7475
- `BUILD_ID`: Build ID from failed job you are testing with (`1696039978221441024` if using job from the example in step 1)
76+
- `PULL_NUMBER`: PUll number for the PR of the rehearsal job you are testing with. If using a rehearsal job.
7577
- `JOB_NAME_SAFE`: Safe job name from the prow job you are testing with (`openshift-pipelines-interop-aws` if using the job from the example in step 1)
7678
- `JOB_NAME`: Full prow job name that you are testing with (`periodic-ci-openshift-pipelines-release-tests-release-v1.11-openshift-pipelines-ocp4.14-lp-interop-openshift-pipelines-interop-aws` if using the job from the example in step 1)
7779
- `FIREWATCH_CONFIG`: Config you would like to test with. Use the [configuration guide](configuration_guide.md) for help.

tests/unittests/functions/report/test_firewatch_functions_report.py

+29-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,33 @@
55

66
class TestReport(ReportBaseTest):
77
def test_report_initialization_with_job_rehearsal(self):
8-
job = Job("rehearse_job1", "job1_safe", "123", "bucket1", self.config)
9-
with self.assertRaises(SystemExit):
8+
job = Job("rehearse-1234-job1", "job1_safe", "123", "bucket1", self.config)
9+
with self.assertRaises(SystemExit) as rc:
1010
Report(self.config, job)
11+
error = rc.exception
12+
self.assertEqual(error.code, 0)
13+
14+
def test_report_initialization_with_job_rehearsal_flag_false_test_failures(self):
15+
job = Job("rehearse-1234-job1", "job1_safe", "123", "bucket1", self.config)
16+
job.has_test_failures = True
17+
with self.assertRaises(SystemExit) as rc:
18+
Report(self.config, job)
19+
error = rc.exception
20+
self.assertEqual(error.code, 0)
21+
22+
def test_report_initialization_with_job_rehearsal_flag_true_no_failures(self):
23+
self.config.fail_with_test_failures = True
24+
job = Job("rehearse-1234-job1", "job1_safe", "123", "bucket1", self.config)
25+
with self.assertRaises(SystemExit) as rc:
26+
Report(self.config, job)
27+
error = rc.exception
28+
self.assertEqual(error.code, 0)
29+
30+
def test_report_initialization_with_job_rehearsal_flag_true_test_failures(self):
31+
self.config.fail_with_test_failures = True
32+
job = Job("rehearse-1234-job1", "job1_safe", "123", "bucket1", self.config)
33+
job.has_test_failures = True
34+
with self.assertRaises(SystemExit) as rc:
35+
Report(self.config, job)
36+
error = rc.exception
37+
self.assertEqual(error.code, 1)

tests/unittests/objects/job/test_firewatch_objects_job_check_is_rehearsal.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
class TestCheckIsRehearsal(JobBaseTest):
66
def test_rehearsal_job_true(self):
7-
job = Job("rehearse_job1", "job1_safe", "123", "bucket1", self.config)
7+
job = Job("rehearse-1234-job1", "job1_safe", "123", "bucket1", self.config)
88
self.assertTrue(job.is_rehearsal)
99

1010
def test_rehearsal_job_false(self):

0 commit comments

Comments
 (0)