Skip to content

Commit

Permalink
[ISV-3903] Add tekton task to check the status of running prow jobs (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mporrato authored Aug 29, 2023
1 parent 704eb70 commit db67f0a
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,24 @@ spec:
- name: results
workspace: results

- name: wait-prow-tests
taskRef:
name: wait-prow-tests
kind: Task
runAfter:
- add-bundle-to-index
params:
- name: pipeline_image
value: "$(params.pipeline_image)"
- name: supported_ocp_versions
value: "$(tasks.get-supported-versions.results.indices_ocp_versions)"
- name: request_url
value: "$(params.git_pr_url)"
- name: github_token_secret_name
value: "$(params.github_token_secret_name)"
- name: github_token_secret_key
value: "$(params.github_token_secret_key)"

finally:

- name: set-github-passed-label
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: wait-prow-tests
spec:
description: Wait for the termination of all prow tests.

params:
- name: pipeline_image
description: The common pipeline image.

- name: supported_ocp_versions
description: |
Space separated list of ocp versions supported by the pipeline
and the bundle
- name: github_host_url
description: |
The GitHub host, adjust this if you run a GitHub enterprise.
default: "https://api.github.com"

- name: request_url
description: |
The GitHub issue or pull request URL where we want to add a new
comment.
- name: github_token_secret_name
description: |
The name of the Kubernetes Secret that contains the GitHub token.
default: github

- name: github_token_secret_key
description: |
The key within the Kubernetes Secret that contains the GitHub token.
default: token

steps:
- name: poll-pr-labels
image: "$(params.pipeline_image)"
env:
- name: GITHUB_TOKEN
valueFrom:
secretKeyRef:
name: "$(params.github_token_secret_name)"
key: "$(params.github_token_secret_key)"
script: |
#!/usr/bin/env bash
set -xe
expected_labels=""
for version in $(params.supported_ocp_versions); do
expected_labels="${expected_labels} --any ocp/${version//./\\.}/(pass|fail)"
done
echo "Waiting for prow tests to finish..."
github-wait-labels \
--github-host-url "$(params.github_host_url)" \
--pull-request-url "$(params.request_url)" \
${expected_labels} \
--poll-interval 30 \
--timeout 3600 \
--verbose \
>/tmp/labels || exit 1
grep -E 'ocp/[^/]+/fail' /tmp/labels && exit 1 || exit 0
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ def __eq__(self, __value: object) -> bool: # pragma: nocover

return self.wait_type == __value.wait_type and self.regexp == __value.regexp

def __repr__(self) -> str:
return f"{self.__class__.__name__}({self.wait_type}, {self.regexp})"


def setup_argparser() -> ap.ArgumentParser:
"""
Expand Down Expand Up @@ -109,12 +112,19 @@ def setup_argparser() -> ap.ArgumentParser:
help="The GitHub pull request URL where we want to wait for labels.",
)

parser.add_argument("--timeout", default=60, help="Timeout for waiting in seconds.")
parser.add_argument(
"--timeout", type=int, default=60, help="Timeout for waiting in seconds."
)

parser.add_argument(
"--poll-interval", default=1, help="Interval between requests in seconds"
"--poll-interval",
type=int,
default=5,
help="Interval between requests in seconds",
)

parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")

return parser


Expand Down Expand Up @@ -157,6 +167,7 @@ def wait_on_pr_labels(
poll_interval_s < timeout_s
), "Timeout needs to be bigger than the poll interval"

LOGGER.debug("Waiting for %s on PR #%s", wait_conditions, pull_request_id)
start_time = time.monotonic()
while time.monotonic() - start_time < timeout_s:
pr_labels = get_pr_labels(repository, pull_request_id)
Expand All @@ -169,14 +180,17 @@ def wait_on_pr_labels(

time.sleep(poll_interval_s)

LOGGER.debug("Timed out!")
return False


def main():
def main() -> int:
parser = setup_argparser()
args = parser.parse_args()

log_level = "INFO"
if args.verbose:
log_level = "DEBUG"
setup_logger(level=log_level)

github_auth = Auth.Token(os.environ["GITHUB_TOKEN"])
Expand All @@ -188,7 +202,7 @@ def main():
repository = github.get_repo(repo_url)
except GithubException as exc:
LOGGER.error("Unable to get repository from GitHub: %s", str(exc))
exit(2)
return 2

conditions = WaitCondition.get_wait_conditions(args)
if not wait_on_pr_labels(
Expand All @@ -198,10 +212,10 @@ def main():
args.timeout,
args.poll_interval,
):
exit(1)
return 1

exit(0)
return 0


if __name__ == "__main__": # pragma: no cover
main()
exit(main())
105 changes: 45 additions & 60 deletions operator-pipeline-images/tests/entrypoints/test_github_wait_labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,115 +23,100 @@ def test_setup_argparser() -> None:
@patch("operatorcert.entrypoints.github_wait_labels.wait_on_pr_labels")
@patch("operatorcert.entrypoints.github_wait_labels.Github.get_repo")
@patch("operatorcert.entrypoints.github_wait_labels.setup_logger")
@patch("operatorcert.entrypoints.github_wait_labels.setup_argparser")
@patch("operatorcert.entrypoints.github_wait_labels.exit")
def test_main(
mock_sys_exit: MagicMock,
mock_setup_argparser: MagicMock,
mock_setup_logger: MagicMock,
mock_github_get_repo: MagicMock,
mock_wait_on_pr_labels: MagicMock,
monkeypatch: Any,
) -> None:
args = MagicMock()
args.any = ["regexp1", "regexp2"]
args.none = ["regexp3"]
args.timeout = 3600
args.poll_interval = 1

args.pull_request_url = "https://github.com/foo/bar/pull/123"
mock_setup_argparser.return_value.parse_args.return_value = args

mock_repo = MagicMock()
mock_github_get_repo.return_value = mock_repo()
mock_wait_on_pr_labels.return_value = True

monkeypatch.setenv("GITHUB_TOKEN", "foo_api_token")

main()
args = [
"github-wait-labels",
"--github-host-url",
"https://api.example.com",
"--pull-request-url",
"https://example.com/namespace/repo/pull/999",
"--any",
r"ocp/4\.10/(pass|fail)",
"--any",
r"ocp/4\.11/(pass|fail)",
"--none",
r"do-not-merge",
"--poll-interval",
"15",
"--timeout",
"1000",
"--verbose",
]

with patch("sys.argv", args):
assert main() == 0

# want to test with __eq__ here to avoid mocking
assert mock_wait_on_pr_labels.call_args[0][2] == [
WaitCondition(WaitType.WaitAny, "regexp1"),
WaitCondition(WaitType.WaitAny, "regexp2"),
WaitCondition(WaitType.WaitNone, "regexp3"),
WaitCondition(WaitType.WaitAny, r"ocp/4\.10/(pass|fail)"),
WaitCondition(WaitType.WaitAny, r"ocp/4\.11/(pass|fail)"),
WaitCondition(WaitType.WaitNone, r"do-not-merge"),
]

assert mock_wait_on_pr_labels.call_args[0][1] == 123
assert mock_wait_on_pr_labels.call_args[0][3] == 3600
assert mock_wait_on_pr_labels.call_args[0][4] == 1

mock_sys_exit.assert_called_once_with(0)
assert mock_wait_on_pr_labels.call_args[0][1] == 999
assert mock_wait_on_pr_labels.call_args[0][3] == 1000
assert mock_wait_on_pr_labels.call_args[0][4] == 15


@patch("operatorcert.entrypoints.github_wait_labels.wait_on_pr_labels")
@patch("operatorcert.entrypoints.github_wait_labels.Github.get_repo")
@patch("operatorcert.entrypoints.github_wait_labels.setup_logger")
@patch("operatorcert.entrypoints.github_wait_labels.setup_argparser")
@patch("operatorcert.entrypoints.github_wait_labels.exit")
def test_main_error(
mock_sys_exit: MagicMock,
mock_setup_argparser: MagicMock,
mock_setup_logger: MagicMock,
mock_github_get_repo: MagicMock,
mock_wait_on_pr_labels: MagicMock,
monkeypatch: Any,
):
args = MagicMock()
args.any = ["regexp1", "regexp2"]
args.none = ["regexp3"]
args.timeout = 3600
args.poll_interval = 1

args.pull_request_url = "https://github.com/foo/bar/pull/123"
mock_setup_argparser.return_value.parse_args.return_value = args

) -> None:
mock_repo = MagicMock()
mock_github_get_repo.return_value = mock_repo()

monkeypatch.setenv("GITHUB_TOKEN", "foo_api_token")
mock_wait_on_pr_labels.return_value = False

mock_sys_exit.side_effect = Exception("So that the utility terminates")

with pytest.raises(Exception):
main()
args = [
"github-wait-labels",
"--pull-request-url",
"https://example.com/namespace/repo/pull/999",
]

mock_sys_exit.assert_called_once_with(1)
with patch("sys.argv", args):
assert main() == 1


@patch("operatorcert.entrypoints.github_wait_labels.wait_on_pr_labels")
@patch("operatorcert.entrypoints.github_wait_labels.Github.get_repo")
@patch("operatorcert.entrypoints.github_wait_labels.setup_logger")
@patch("operatorcert.entrypoints.github_wait_labels.setup_argparser")
@patch("operatorcert.entrypoints.github_wait_labels.exit")
def test_main_get_repo_exception(
mock_sys_exit: MagicMock,
mock_setup_argparser: MagicMock,
mock_setup_logger: MagicMock,
mock_github_get_repo: MagicMock,
mock_wait_on_pr_labels: MagicMock,
monkeypatch: Any,
):
args = MagicMock()
args.any = ["regexp1", "regexp2"]
args.none = ["regexp3"]
args.timeout = 3600
args.poll_interval = 1

args.pull_request_url = "https://github.com/foo/bar/pull/123"
mock_setup_argparser.return_value.parse_args.return_value = args

) -> None:
mock_repo = MagicMock()
mock_github_get_repo.side_effect = GithubException(0, "err", None)

monkeypatch.setenv("GITHUB_TOKEN", "foo_api_token")
mock_wait_on_pr_labels.return_value = False

mock_sys_exit.side_effect = Exception("So that the utility terminates")

with pytest.raises((GithubException, Exception)):
main()
args = [
"github-wait-labels",
"--pull-request-url",
"https://example.com/namespace/repo/pull/999",
]

mock_sys_exit.assert_called_once_with(2)
with patch("sys.argv", args):
assert main() == 2


def test_get_pr_labels():
Expand Down

0 comments on commit db67f0a

Please sign in to comment.