diff --git a/.tekton/pull-request.yaml b/.tekton/pull-request.yaml index c09062d9cf..b8b48895f7 100644 --- a/.tekton/pull-request.yaml +++ b/.tekton/pull-request.yaml @@ -69,15 +69,12 @@ spec: value: - tasks := strings.any_prefix_match(input, ["task/", "hack/", ".tekton/"]) - tasks_pipelines := strings.any_prefix_match(input, ["task/", "pipelines/", "hack/", ".tekton/"]) - - | - e2e_tests if { - some file in input - strings.any_prefix_match(file, ["task/", "pipelines/", "hack/", ".tekton/"]) - not endswith(file, "/OWNERS") - } - check_partner_tasks := strings.any_prefix_match(input, ["partners/", "hack/", ".tekton/"]) runAfter: - build-appstudio-utils + workspaces: + - name: source + workspace: workspace - name: task-lint-check when: - input: "tasks" @@ -208,9 +205,9 @@ spec: - name: source - name: e2e-tests when: - - input: "e2e_tests" + - input: "$(tasks.task-switchboard.results.run-e2e)" operator: "in" - values: ["$(tasks.task-switchboard.results.bindings[*])"] + values: ["execute_e2e"] params: - name: e2e_test_namespace value: $(params.e2e_test_namespace) @@ -286,9 +283,9 @@ spec: finally: - name: e2e-cleanup when: - - input: "e2e_tests" + - input: "$(tasks.task-switchboard.results.run-e2e)" operator: "in" - values: ["$(tasks.task-switchboard.results.bindings[*])"] + values: ["execute_e2e"] params: - name: e2e_test_namespace value: $(params.e2e_test_namespace) @@ -306,9 +303,9 @@ spec: oc delete --ignore-not-found eventlisteners --all -n $(params.e2e_test_namespace) - name: pull-request-status-message when: - - input: "tasks_pipelines" + - input: "$(tasks.task-switchboard.results.run-e2e)" operator: "in" - values: ["$(tasks.task-switchboard.results.bindings[*])"] + values: ["execute_e2e"] taskRef: resolver: git params: diff --git a/.tekton/scripts/determine-if-e2e-execution-needed.py b/.tekton/scripts/determine-if-e2e-execution-needed.py new file mode 100755 index 0000000000..4a4bcef070 --- /dev/null +++ b/.tekton/scripts/determine-if-e2e-execution-needed.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 + +import os +import sys +import json +import urllib.error +import urllib.request +import subprocess + +# Pipelines currently covered by e2e tests +pipelines_covered_by_e2e = ["docker-build", "docker-build-oci-ta", "docker-build-multi-platform-oci-ta", "fbc-builder"] + +# Task list which are covered by e2e tests, generated dynamically +tasks_covered_by_e2e = [] + +# Otherthan tasks and pipelines, related files for which e2e tests needs to be executed +files_covered_by_e2e = [".tekton/pull-request.yaml", ".tekton/tasks/e2e-test.yaml", ".tekton/scripts/determine-if-e2e-execution-needed.py"] + +def add_only_unique_task_names(task_list): + for task_name in task_list: + if task_name not in tasks_covered_by_e2e: + tasks_covered_by_e2e.append(task_name) + +def get_tasks_covered_by_e2e(): + for pipeline_name in pipelines_covered_by_e2e: + pipeline_path = f"pipelines/{pipeline_name}/{pipeline_name}.yaml" + # Get the task names from pipeline spec + result = subprocess.run(["yq", "-e", ".spec.tasks[].taskRef.name", pipeline_path], capture_output=True, text=True) + if result.stderr != "": + sys.stderr.write(f"[ERROR] failed to get tasks inside spec.tasks: {result.stderr}\n") + sys.exit(1) + output = result.stdout + task_names = output.split() + add_only_unique_task_names(task_names) + # Get the task names from pipeline finally + result = subprocess.run([f"yq -e '.spec.finally[].taskRef.name' {pipeline_path}"], shell=True, capture_output=True, text=True) + if result.stderr != "": + sys.stderr.write(f"[ERROR] failed to get tasks inside .spec.finally: {result.stderr}\n") + sys.exit(1) + output = result.stdout + task_names = output.split() + add_only_unique_task_names(task_names) + +def get_changed_files_from_pr(pull_number): + updated_files = [] + base_url = "https://api.github.com" + repo = "konflux-ci/build-definitions" + url = f"{base_url}/repos/{repo}/pulls/{pull_number}/files" + req = urllib.request.Request(url=url, method="GET") + try: + with urllib.request.urlopen(req) as resp: + if resp.status != 200: + sys.stderr.write(f"[ERROR] Unknown response status code: {resp.status}\n") + sys.exit(1) + response_in_json = json.loads(resp.read()) + for object in response_in_json: + updated_files.append(object['filename']) + except urllib.error.HTTPError as e: + sys.stderr.write(f"[ERROR] got error response: {e.read()} with status {e.code}\n") + sys.exit(1) + return updated_files + +def does_updated_files_covered_by_e2e(updated_files): + required_to_run_e2e = False + for file_path in updated_files: + if file_path.startswith("task/"): + task_name = file_path.split("/")[1] + if task_name in tasks_covered_by_e2e: + required_to_run_e2e = True + break + elif file_path.startswith("pipelines/"): + pipeline_name = file_path.split("/")[1] + if pipeline_name in pipelines_covered_by_e2e: + required_to_run_e2e = True + break + elif file_path in files_covered_by_e2e: + required_to_run_e2e = True + break + else: + sys.stderr.write("No need to run e2e tests\n") + return required_to_run_e2e + +if __name__ == '__main__': + if len(sys.argv) != 2: + sys.stderr.write("[ERROR] provide correct number of arguments\n") + sys.exit(1) + pr_number = sys.argv[1] + get_tasks_covered_by_e2e() + updated_files = get_changed_files_from_pr(pr_number) + required_to_run_e2e = does_updated_files_covered_by_e2e(updated_files) + if required_to_run_e2e: + print("execute_e2e") + else: + print("dont_execute_e2e") diff --git a/.tekton/tasks/task-switchboard.yaml b/.tekton/tasks/task-switchboard.yaml index 1ad0d93ae8..659a51c6bb 100644 --- a/.tekton/tasks/task-switchboard.yaml +++ b/.tekton/tasks/task-switchboard.yaml @@ -21,6 +21,8 @@ spec: results: - name: bindings type: array + - name: run-e2e + type: string steps: - name: evaluate image: $(params.utils_image) @@ -32,6 +34,7 @@ spec: key: "git-provider-token" args: - "$(params.expressions[*])" + workingDir: $(workspaces.source.path)/source script: | #!/bin/bash set -o errexit @@ -53,3 +56,8 @@ spec: 'data[_]' \ | jq '[.result.[].expressions.[].value | to_entries | .[] | select(.value == true) | .key]' \ | tee "$(results.bindings.path)" + + # Output is "execute_e2e" or "dont_execute_e2e" based on files changed in pr + if [[ -n "${pr_number}" ]]; then + .tekton/scripts/determine-if-e2e-execution-needed.py "${pr_number}" | tr -d '\n' | tee "$(results.run-e2e.path)" + fi