diff --git a/.gitlab/ci/pipelines/before_merging.yml b/.gitlab/ci/pipelines/before_merging.yml index d08f74db49f225125492aef53fc9905daf80532e..cd521557ce71192f581c3768bf78e0fcdbd75cbb 100644 --- a/.gitlab/ci/pipelines/before_merging.yml +++ b/.gitlab/ci/pipelines/before_merging.yml @@ -7105,7 +7105,7 @@ oc.unit:non-proto-x86_64: expire_in: 1 day paths: - test_results - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: test_results/*.xml when: always @@ -7148,7 +7148,7 @@ oc.unit:other-x86_64: expire_in: 1 day paths: - test_results - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: test_results/*.xml when: always @@ -7191,7 +7191,7 @@ oc.unit:proto-x86_64: expire_in: 1 day paths: - test_results - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: test_results/*.xml when: always @@ -7552,7 +7552,7 @@ tezt: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi + - ./scripts/ci/merge_coverage.sh variables: JUNIT: tezt-junit.xml TEZT_VARIANT: "" @@ -7570,7 +7570,7 @@ tezt: - tezt-*.log - tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json - $JUNIT - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: $JUNIT when: always @@ -7619,7 +7619,7 @@ tezt-memory-3k: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi + - ./scripts/ci/merge_coverage.sh variables: JUNIT: tezt-junit.xml TEZT_VARIANT: -memory_3k @@ -7637,7 +7637,7 @@ tezt-memory-3k: - tezt-*.log - tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json - $JUNIT - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: $JUNIT when: always @@ -7685,7 +7685,7 @@ tezt-memory-4k: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi + - ./scripts/ci/merge_coverage.sh variables: JUNIT: tezt-junit.xml TEZT_VARIANT: -memory_4k @@ -7703,7 +7703,7 @@ tezt-memory-4k: - tezt-*.log - tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json - $JUNIT - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: $JUNIT when: always @@ -7752,7 +7752,7 @@ tezt-time-sensitive: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi + - ./scripts/ci/merge_coverage.sh variables: JUNIT: tezt-junit.xml TEZT_VARIANT: -time_sensitive @@ -7770,7 +7770,7 @@ tezt-time-sensitive: - tezt-*.log - tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json - $JUNIT - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: $JUNIT when: always @@ -7819,7 +7819,6 @@ tezt-slow: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi variables: JUNIT: tezt-junit.xml TEZT_VARIANT: -slow @@ -7884,7 +7883,7 @@ tezt-flaky: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi + - ./scripts/ci/merge_coverage.sh variables: JUNIT: tezt-junit.xml TEZT_VARIANT: -flaky @@ -7902,7 +7901,7 @@ tezt-flaky: - tezt-*.log - tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json - $JUNIT - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: $JUNIT when: always @@ -7947,7 +7946,6 @@ tezt:static-binaries: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi variables: JUNIT: tezt-junit.xml TEZT_VARIANT: "" diff --git a/.gitlab/ci/pipelines/schedule_extended_test.yml b/.gitlab/ci/pipelines/schedule_extended_test.yml index a80706826e497c3e89d6d8f26da5d169d4dfd4a9..6a859d63765b165402656ab5ac929a3f6c9f92f9 100644 --- a/.gitlab/ci/pipelines/schedule_extended_test.yml +++ b/.gitlab/ci/pipelines/schedule_extended_test.yml @@ -6759,7 +6759,7 @@ oc.unit:non-proto-x86_64: expire_in: 1 day paths: - test_results - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: test_results/*.xml when: always @@ -6792,7 +6792,7 @@ oc.unit:other-x86_64: expire_in: 1 day paths: - test_results - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: test_results/*.xml when: always @@ -6825,7 +6825,7 @@ oc.unit:proto-x86_64: expire_in: 1 day paths: - test_results - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: test_results/*.xml when: always @@ -7070,7 +7070,7 @@ tezt: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi + - ./scripts/ci/merge_coverage.sh variables: JUNIT: tezt-junit.xml TEZT_VARIANT: "" @@ -7088,7 +7088,7 @@ tezt: - tezt-*.log - tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json - $JUNIT - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: $JUNIT when: always @@ -7127,7 +7127,7 @@ tezt-memory-3k: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi + - ./scripts/ci/merge_coverage.sh variables: JUNIT: tezt-junit.xml TEZT_VARIANT: -memory_3k @@ -7145,7 +7145,7 @@ tezt-memory-3k: - tezt-*.log - tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json - $JUNIT - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: $JUNIT when: always @@ -7183,7 +7183,7 @@ tezt-memory-4k: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi + - ./scripts/ci/merge_coverage.sh variables: JUNIT: tezt-junit.xml TEZT_VARIANT: -memory_4k @@ -7201,7 +7201,7 @@ tezt-memory-4k: - tezt-*.log - tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json - $JUNIT - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: $JUNIT when: always @@ -7240,7 +7240,7 @@ tezt-time-sensitive: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi + - ./scripts/ci/merge_coverage.sh variables: JUNIT: tezt-junit.xml TEZT_VARIANT: -time_sensitive @@ -7258,7 +7258,7 @@ tezt-time-sensitive: - tezt-*.log - tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json - $JUNIT - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: $JUNIT when: always @@ -7296,7 +7296,6 @@ tezt-slow: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi variables: JUNIT: tezt-junit.xml TEZT_VARIANT: -slow @@ -7350,7 +7349,7 @@ tezt-flaky: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi + - ./scripts/ci/merge_coverage.sh variables: JUNIT: tezt-junit.xml TEZT_VARIANT: -flaky @@ -7368,7 +7367,7 @@ tezt-flaky: - tezt-*.log - tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json - $JUNIT - - $BISECT_FILE + - $BISECT_FILE/$CI_JOB_NAME_SLUG.* reports: junit: $JUNIT when: always @@ -7403,7 +7402,6 @@ tezt:static-binaries: fail --junit ${JUNIT} --from-record tezt/records --job ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count ${TEZT_PARALLEL} --retry ${TEZT_RETRY} - - if [ -n "${BISECT_FILE:-}" ]; then ./scripts/ci/merge_coverage.sh; fi variables: JUNIT: tezt-junit.xml TEZT_VARIANT: "" diff --git a/ci/bin/code_verification.ml b/ci/bin/code_verification.ml index 6cb24120ab6301c5ba9a445004d4b264777cffb4..e7d16f4cc0b05d9cfba82ffc6c15871498822f22 100644 --- a/ci/bin/code_verification.ml +++ b/ci/bin/code_verification.ml @@ -272,7 +272,6 @@ let job_tezt ~__POS__ ?rules ?parallel ?(tags = ["gcp_tezt"]) ~name ${CI_NODE_INDEX:-1}/${CI_NODE_TOTAL:-1} --record \ tezt-results-${CI_NODE_INDEX:-1}${TEZT_VARIANT}.json --job-count \ ${TEZT_PARALLEL} --retry ${TEZT_RETRY}"; - "if [ -n \"${BISECT_FILE:-}\" ]; then ./scripts/ci/merge_coverage.sh; fi"; ] (** Tezt tag selector string. @@ -381,11 +380,13 @@ let jobs pipeline_type = : tezos_job = jobs_with_coverage_output := tezos_job :: !jobs_with_coverage_output ; tezos_job |> enable_coverage_location + |> append_script ["./scripts/ci/merge_coverage.sh"] |> add_artifacts ~expire_in ~name:"coverage-files-$CI_JOB_ID" ~when_:On_success - ["$BISECT_FILE"] + (* Store merged .coverage files or [.corrupt.json] files. *) + ["$BISECT_FILE/$CI_JOB_NAME_SLUG.*"] in (* Stages *) let trigger_stage, make_dependencies = @@ -1060,13 +1061,9 @@ let jobs pipeline_type = make_rules ~changes:changeset_octez ~dependent:true () in let job_unit_test ~__POS__ ?(image = Images.runtime_build_dependencies) - ?timeout ?parallel_vector ~arch ~name ?(enable_coverage = true) - ~make_targets () : tezos_job = + ?timeout ?parallel_vector ~arch ~name ~make_targets () : tezos_job = let arch_string = arch_to_string arch in - let script = - ["make $MAKE_TARGETS"] - @ if enable_coverage then ["./scripts/ci/merge_coverage.sh"] else [] - in + let script = ["make $MAKE_TARGETS"] in let dependencies = build_dependencies arch in let variables = [ @@ -1087,34 +1084,27 @@ let jobs pipeline_type = Some (Vector n) ) | None -> (variables, None) in - let job = - job - ?timeout - ?parallel - ~__POS__ - ~retry:2 - ~name - ~stage:Stages.test - ~image - ~arch - ~dependencies - ~rules - ~variables - ~artifacts: - (artifacts - ~name:"$CI_JOB_NAME-$CI_COMMIT_SHA-${ARCH}" - ["test_results"] - ~reports:(reports ~junit:"test_results/*.xml" ()) - ~expire_in:(Duration (Days 1)) - ~when_:Always) - ~before_script: - (before_script ~source_version:true ~eval_opam:true []) - script - in - if enable_coverage then - job |> enable_coverage_instrumentation - |> enable_coverage_output_artifact - else job + job + ?timeout + ?parallel + ~__POS__ + ~retry:2 + ~name + ~stage:Stages.test + ~image + ~arch + ~dependencies + ~rules + ~variables + ~artifacts: + (artifacts + ~name:"$CI_JOB_NAME-$CI_COMMIT_SHA-${ARCH}" + ["test_results"] + ~reports:(reports ~junit:"test_results/*.xml" ()) + ~expire_in:(Duration (Days 1)) + ~when_:Always) + ~before_script:(before_script ~source_version:true ~eval_opam:true []) + script in let oc_unit_non_proto_x86_64 = job_unit_test @@ -1124,6 +1114,7 @@ let jobs pipeline_type = ~image:Images.runtime_build_test_dependencies ~make_targets:["test-nonproto-unit"] () + |> enable_coverage_instrumentation |> enable_coverage_output_artifact in let oc_unit_other_x86_64 = (* Runs unit tests for contrib. *) @@ -1133,6 +1124,7 @@ let jobs pipeline_type = ~arch:Amd64 ~make_targets:["test-other-unit"] () + |> enable_coverage_instrumentation |> enable_coverage_output_artifact in let oc_unit_proto_x86_64 = (* Runs unit tests for protocol. *) @@ -1142,8 +1134,11 @@ let jobs pipeline_type = ~arch:Amd64 ~make_targets:["test-proto-unit"] () + |> enable_coverage_instrumentation |> enable_coverage_output_artifact in let oc_unit_non_proto_arm64 = + (* No coverage for arm64 jobs -- the code they test is a + subset of that tested by x86_64 unit tests. *) job_unit_test ~__POS__ ~name:"oc.unit:non-proto-arm64" @@ -1151,9 +1146,6 @@ let jobs pipeline_type = ~arch:Arm64 (* The [lib_benchmark] unit tests require Python *) ~image:Images.runtime_build_test_dependencies ~make_targets:["test-nonproto-unit"; "test-webassembly"] - (* No coverage for arm64 jobs -- the code they test is a - subset of that tested by x86_64 unit tests. *) - ~enable_coverage:false () in let oc_unit_webassembly_x86_64 = diff --git a/ci/bin/tezos_ci.ml b/ci/bin/tezos_ci.ml index 5e018f0f6498e9ed20662b32f3e79726035d5c29..526b4eb0e41d1af292490e09276d14b0308f7093 100644 --- a/ci/bin/tezos_ci.ml +++ b/ci/bin/tezos_ci.ml @@ -622,3 +622,6 @@ let check_files ~remove_extra_files ?(exclude = fun _ -> false) () = \ rm %s" (error_not_generated |> String_set.elements |> String.concat " ")) ; if !Cli.has_error then exit 1 + +let append_script script tezos_job = + map_job tezos_job @@ fun job -> {job with script = job.script @ script} diff --git a/ci/bin/tezos_ci.mli b/ci/bin/tezos_ci.mli index bee791753ca33574b57fe03e220485f81f1f1900..d5ee82187d2574f2ed70ce48a9096535521b6e62 100644 --- a/ci/bin/tezos_ci.mli +++ b/ci/bin/tezos_ci.mli @@ -291,3 +291,6 @@ val add_artifacts : [job], unless [allow_overwrite] is true (default is [false]). *) val append_variables : ?allow_overwrite:bool -> Gitlab_ci.Types.variables -> tezos_job -> tezos_job + +(** Append to the [script:] section of a job. *) +val append_script : string list -> tezos_job -> tezos_job diff --git a/scripts/ci/download_coverage/download.ml b/scripts/ci/download_coverage/download.ml index 30658f6dda0da9641f5e272ea849d8ca1690c23d..588b16cfe2f8a2c2e09aa1e98a1c8b9765d8df79 100644 --- a/scripts/ci/download_coverage/download.ml +++ b/scripts/ci/download_coverage/download.ml @@ -66,11 +66,24 @@ let fetch_pipeline_coverage_from_jobs pipeline = let job_id = JSON.(job |-> "id" |> as_int) in let job_name = JSON.(job |-> "name" |> as_string) in let job_status = JSON.(job |-> "status" |> as_string) in + (* Based on [Utils.slugify] from + https://gitlab.com/gitlab-org/gitlab/blob/master/gems/gitlab-utils/lib/gitlab/utils.rb#L58 *) + let slugify str = + let str = + String.map + (function + | ('a' .. 'z' | 'A' .. 'Z' | '0' .. '9') as c -> c | _ -> '-') + str + in + let str = String.sub str 0 (min (String.length job_name) 63) in + Base.replace_string (rex "^-+|-+$") ~by:"" str + in let artifact_name = - Base.replace_string (rex "[\\\\/_ @\\[\\]]+") job_name ~by:"-" - ^ ".coverage" - (* See for [scripts/ci/merge_coverage.sh] for details on how - job_names are mangled into coverage trace artifact paths. *) + (* Coverage traces are stored in [${CI_JOB_NAME_SLUG}.coverage] + (see [scripts/ci/merge_coverage.sh]) for full details, + and see https://docs.gitlab.com/ee/ci/variables/predefined_variables.html + for the details on CI_JOB_NAME_SLUG. *) + slugify job_name ^ ".coverage" in let artifact_path = coverage_traces_directory // artifact_name in if diff --git a/scripts/ci/merge_coverage.sh b/scripts/ci/merge_coverage.sh index 589cc779f98026cc6417f31eea04ae5351b51924..2ecf7fa3a04f814c7e0c2d25886439d2db45da8c 100755 --- a/scripts/ci/merge_coverage.sh +++ b/scripts/ci/merge_coverage.sh @@ -2,29 +2,27 @@ set -eu -# Pass [-s] to [tr] to squeeze repeat (use short option) for BusyBox -# compatibility. -COVERAGE_MERGED=$(echo "$CI_JOB_NAME" | tr -s '[\/_ @[]+' '-') +coverage_merged="$CI_JOB_NAME_SLUG".coverage # If BISECT_FILE is not set, or the ci--no-coverage label is set, we # do not attempt to merge the coverage files if [ -z "${BISECT_FILE:-}" ] || echo "${CI_MERGE_REQUEST_LABELS:-}" | grep -q '\(^\|,\)ci--no-coverage\($\|,\)'; then - rm -f "$BISECT_FILE"*.coverage + if [ -n "${BISECT_FILE:-}" ]; then + rm -f "$BISECT_FILE"*.coverage + fi echo "Coverage is disabled." -elif bisect-ppx-report merge --coverage-path "$BISECT_FILE" "$COVERAGE_MERGED".coverage; then +elif bisect-ppx-report merge --coverage-path "$BISECT_FILE" "$coverage_merged"; then # Merge was successful, meaning that no corrupted files were found - COVERAGE_MERGED="$COVERAGE_MERGED".coverage rm -f "$BISECT_FILE"*.coverage - mv "$COVERAGE_MERGED" "$BISECT_FILE" - echo "Merged coverage files to ${BISECT_FILE}/${COVERAGE_MERGED}" + mv "$coverage_merged" "$BISECT_FILE" + echo "Merged coverage files to ${BISECT_FILE}${coverage_merged}" else # Merge was not successful, meaning that coverage was corrupted. # Store failure details as an artifact that is treated in the job # `unified_coverage`. rm -f "$BISECT_FILE"*.coverage - COVERAGE_MERGED="$COVERAGE_MERGED".corrupt.json + coverage_corrupt="${BISECT_FILE}${CI_JOB_NAME_SLUG}".corrupt.json printf '{"job_id": %s, "job_name": "%s", "job_web_url": "%s"}' \ - "$CI_JOB_ID" "$CI_JOB_NAME" "$CI_JOB_URL" > "$COVERAGE_MERGED" - mv "$COVERAGE_MERGED" "$BISECT_FILE" - echo "Corrupt coverage files detected, wrote ${BISECT_FILE}${COVERAGE_MERGED}" + "$CI_JOB_ID" "$CI_JOB_NAME" "$CI_JOB_URL" > "$coverage_corrupt" + echo "Corrupt coverage files detected, wrote ${coverage_corrupt}" fi