| # Copyright 2019 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """Recipe for uploading build and test outputs.""" |
| |
| import textwrap |
| |
| from recipe_engine.recipe_api import Property |
| from recipe_engine.config import List |
| |
| DEPS = [ |
| "fuchsia/build", |
| "fuchsia/checkout", |
| "fuchsia/tricium_analyze", |
| "recipe_engine/buildbucket", |
| "recipe_engine/context", |
| "recipe_engine/file", |
| "recipe_engine/json", |
| "recipe_engine/path", |
| "recipe_engine/properties", |
| "recipe_engine/raw_io", |
| ] |
| |
| PROPERTIES = { |
| "enabled_analyzers": Property(kind=List(str), help="Enabled analyzers", default=()), |
| "suggest_fx": Property( |
| kind=bool, help="Value for api.tricium_analyze.suggest_fx", default=True |
| ), |
| } |
| |
| |
| def RunSteps(api, enabled_analyzers, suggest_fx): |
| checkout = api.checkout.fuchsia_with_options( |
| manifest="minimal", |
| path=api.path["start_dir"].join("checkout"), |
| remote="https://fuchsia.googlesource.com/fuchsia", |
| ) |
| api.tricium_analyze.build_results = api.build.with_options( |
| checkout=checkout, fint_params_path="fint_params/tricium.textproto" |
| ) |
| api.path.mock_add_paths( |
| checkout.root_dir.join("tools", "mdlint", "rules", "respectful_code_words.json") |
| ) |
| |
| api.tricium_analyze.suggest_fx = suggest_fx |
| api.tricium_analyze.checkout = checkout |
| |
| api.tricium_analyze.check_commit_message() |
| |
| exts = [ |
| "cpp", |
| "go", |
| "gn", |
| "md", |
| "rs", |
| "py", |
| "o", |
| ] |
| with api.context(cwd=checkout.root_dir): |
| filenames = [api.path.sep.join(["path", "to", f"file.{ext}"]) for ext in exts] |
| # Re-analyzing another C++ file shouldn't re-run the analysis. |
| api.tricium_analyze( |
| filenames, |
| enabled_analyzers=enabled_analyzers, |
| enabled_luci_analyzers=["Spellchecker"], |
| ) |
| |
| |
| def GenTests(api): |
| def change_diff_data(filename): |
| # This data isn't very realistic, but we only care about the line |
| # numbers - the file contents don't matter. |
| diff = f"""\ |
| diff --git a/{filename} b/{filename} |
| index e684c1e..a76a10e 100644 |
| --- a/{filename} |
| +++ b/{filename} |
| @@ -25,0 +26,23 @@ |
| +foo |
| +bar |
| @@ -336,0 +360,34 @@ |
| +foo |
| +bar |
| @@ -358,105 +414,0 @@ |
| -foo |
| -bar |
| """ |
| diff = textwrap.dedent(diff) |
| return api.step_data( |
| f"analyze {filename}.get change diff", |
| api.raw_io.stream_output_text(diff), |
| ) |
| |
| def formatted_diff_data(filename): |
| # This data isn't very realistic, but we only care about the line |
| # numbers - the file contents don't matter. |
| diff = f"""\ |
| diff --git a/{filename} b/{filename} |
| index e684c1e..a76a10e 100644 |
| --- a/{filename} |
| +++ b/{filename} |
| @@ -32 +31,0 @@ |
| -foo |
| @@ -33,0 +33 @@ |
| +foo |
| @@ -46 +46 @@ |
| - ] |
| + ] |
| @@ -369,2 +368,0 @@ |
| -foo |
| -bar |
| @@ -374,0 +373,2 @@ |
| +bar |
| +foo |
| """ |
| diff = textwrap.dedent(diff) |
| return api.step_data( |
| f"analyze {filename}.get formatted diff", |
| api.raw_io.stream_output_text(diff), |
| ) |
| |
| clang_tidy_errors_json = { |
| "Diagnostics": [ |
| { |
| "DiagnosticMessage": { |
| "FileOffset": 12, |
| "Message": "error", |
| "FilePath": "../../path/to/file.cpp", |
| }, |
| "DiagnosticName": "fuchsia-default", |
| }, |
| { |
| "DiagnosticMessage": { |
| "FileOffset": 16, |
| "Message": "error", |
| "FilePath": "../../path/to/file.cpp", |
| }, |
| "DiagnosticName": "fuchsia-default", |
| }, |
| ] |
| } |
| |
| clang_tidy_errors_json_bad_offset = { |
| "Diagnostics": [ |
| { |
| "DiagnosticMessage": { |
| "FileOffset": 65, |
| "Message": "error", |
| "FilePath": "../../path/to/file.cpp", |
| }, |
| "DiagnosticName": "fuchsia-default", |
| } |
| ] |
| } |
| |
| go_vet_output = """go: finding github.com/julienschmidt/httprouter v1.2.0 |
| go: extracting golang.org/x/text v0.3.2 |
| # fuchsia.googlesource.com/tools/artifacts |
| { |
| "fuchsia.googlesource.com/tools/artifacts": { |
| "unreachable": [ |
| { |
| "posn": "[START_DIR]/checkout/path/to/file.go:39:2", |
| "message": "unreachable code" |
| }, |
| { |
| "posn": "[START_DIR]/checkout/path/to/other_file.go:10:2", |
| "message": "unreachable code" |
| } |
| ] |
| } |
| } |
| """ |
| |
| go_vet_output_no_warnings = """go: finding github.com/julienschmidt/httprouter v1.2.0 |
| go: extracting golang.org/x/text v0.3.2 |
| # fuchsia.googlesource.com/tools/artifacts |
| {} |
| """ |
| |
| # These are sample response returned from a Gerrit API query request. They are |
| # equivalent to a response like: |
| # $ curl -b ~/.gitcookies https://fuchsia-review.googlesource.com/a/changes/407720/detail |
| # However, many fields are omitted. |
| no_commit_tag = { |
| "labels": {"Code-Review": {}, "Commit-Message-has-tags": {}}, |
| "current_revision": "123abc", |
| "revisions": { |
| "123abc": {"_number": 3, "commit": {"message": "[foo] Add tests"}} |
| }, |
| } |
| |
| valid_commit_tag = { |
| "labels": { |
| "Code-Review": {}, |
| "Commit-Message-has-tags": {"all": [{"_account_id": 37097}]}, |
| }, |
| "current_revision": "123abc", |
| "revisions": { |
| "123abc": {"_number": 3, "commit": {"message": "[foo] Add tests"}} |
| }, |
| } |
| |
| no_commit_message_label = { |
| "labels": {"Code-Review": {}}, |
| "current_revision": "123abc", |
| "revisions": { |
| "123abc": {"_number": 3, "commit": {"message": "[foo] Add tests"}} |
| }, |
| } |
| |
| non_inclusive_commit_message = { |
| "labels": { |
| "Code-Review": {}, |
| "Commit-Message-has-tags": {"all": [{"_account_id": 37097}]}, |
| }, |
| "current_revision": "123abc", |
| "revisions": { |
| "123abc": { |
| "_number": 3, |
| "commit": {"message": "[foo] master"}, # inclusive-language: ignore |
| }, |
| }, |
| } |
| |
| try_build = api.buildbucket.try_build( |
| git_repo="https://fuchsia.googlesource.com/fuchsia", patch_set=3 |
| ) |
| |
| yield ( |
| api.test("no_analysis") |
| + try_build |
| + api.step_data( |
| "check commit tags.get change details", api.json.output(valid_commit_tag) |
| ) |
| ) |
| |
| yield ( |
| api.test("clang_tidy") |
| + try_build |
| + api.properties(enabled_analyzers=["CLANGTIdY"]) # check case-insensitivity |
| + api.step_data( |
| "check commit tags.get change details", api.json.output(valid_commit_tag) |
| ) |
| + api.step_data( |
| "analyze path/to/file.cpp.clang-tidy.load clang_tidy_fixes.yaml", |
| stdout=api.json.output(clang_tidy_errors_json), |
| ) |
| ) |
| |
| yield ( |
| api.test("clang_tidy_error") |
| + try_build |
| + api.properties(enabled_analyzers=["ClangTidy"]) |
| + api.step_data( |
| "check commit tags.get change details", api.json.output(valid_commit_tag) |
| ) |
| + api.step_data( |
| "analyze path/to/file.cpp.clang-tidy.clang-tidy-diff.py", |
| retcode=1, |
| ) |
| ) |
| |
| yield ( |
| api.test("clang_tidy_bad_offset") |
| + try_build |
| + api.properties(enabled_analyzers=["ClangTidy"]) |
| + api.step_data( |
| "check commit tags.get change details", api.json.output(valid_commit_tag) |
| ) |
| + api.step_data( |
| "analyze path/to/file.cpp.clang-tidy.load clang_tidy_fixes.yaml", |
| stdout=api.json.output(clang_tidy_errors_json_bad_offset), |
| ) |
| ) |
| |
| yield ( |
| api.test("go_vet") |
| + try_build |
| + api.properties(enabled_analyzers=["GoVet"]) |
| + api.step_data( |
| "check commit tags.get change details", api.json.output(valid_commit_tag) |
| ) |
| + api.step_data( |
| "analyze path/to/file.go.go vet.run", |
| stderr=api.raw_io.output_text(go_vet_output), |
| ) |
| ) |
| |
| yield ( |
| api.test("go_vet_build_fails") |
| + try_build |
| + api.properties(enabled_analyzers=["GoVet"]) |
| + api.step_data( |
| "check commit tags.get change details", api.json.output(valid_commit_tag) |
| ) |
| + api.step_data("analyze path/to/file.go.go vet.run", retcode=1) |
| ) |
| |
| yield ( |
| api.test("go_vet_no_warnings") |
| + try_build |
| + api.properties(enabled_analyzers=["GoVet"]) |
| + api.step_data( |
| "check commit tags.get change details", api.json.output(valid_commit_tag) |
| ) |
| + api.step_data( |
| "analyze path/to/file.go.go vet.run", |
| stderr=api.raw_io.output_text(go_vet_output_no_warnings), |
| ) |
| ) |
| |
| yield ( |
| api.test("clang_format") |
| + try_build |
| + api.properties(enabled_analyzers=["ClangFormat"]) |
| + api.step_data( |
| "check commit tags.get change details", api.json.output(valid_commit_tag) |
| ) |
| + change_diff_data("path/to/file.cpp") |
| + formatted_diff_data("path/to/file.cpp") |
| ) |
| |
| yield ( |
| api.test("gofmt") |
| + try_build |
| + api.properties(enabled_analyzers=["GoFmt"]) |
| + api.step_data( |
| "check commit tags.get change details", api.json.output(valid_commit_tag) |
| ) |
| + change_diff_data("path/to/file.go") |
| + formatted_diff_data("path/to/file.go") |
| ) |
| |
| yield ( |
| api.test("no_commit_tag") |
| + try_build |
| + api.properties(enabled_analyzers=["CommitTag"]) |
| + api.step_data( |
| "check commit tags.get change details", api.json.output(no_commit_tag) |
| ) |
| ) |
| |
| yield ( |
| api.test("valid_commit_tag") |
| + try_build |
| + api.properties(enabled_analyzers=["CommitTag"]) |
| + api.step_data( |
| "check commit tags.get change details", api.json.output(valid_commit_tag) |
| ) |
| ) |
| |
| yield ( |
| api.test("no_commit_message") |
| + try_build |
| + api.properties(enabled_analyzers=["CommitTag"]) |
| + api.step_data( |
| "check commit tags.get change details", |
| api.json.output(no_commit_message_label), |
| ) |
| ) |
| |
| # The following diff does not include the last two lines containing the word |
| # `master` so they should be excluded from the inclusivity check. |
| file_contents = """file contents: |
| non-inclusive word master |
| url http://master-url.com http://master-url2.com |
| master #inclusive-language:disable |
| notmaster |
| master # inclusive-language: enable |
| master |
| master # inclusive-language: ignore |
| master |
| master |
| master |
| """ |
| diff = """\ |
| diff --git a/{0} b/{0} |
| index e684c1e..a76a10e 100644 |
| --- a/{0} |
| +++ b/{0} |
| @@ -2,0 +2,8 @@ |
| +master |
| +url http://master-url.com http://master-url2.com (urls should be excluded) |
| +master #inclusive-language:disable (should be ignored) |
| +notmaster |
| +master # inclusive-language: enable |
| +master |
| +master # inclusive-language: ignore (should be ignored) |
| +master |
| @@ -8,1 +9,0 @@ |
| -slave |
| """ |
| diff = textwrap.dedent(diff) |
| |
| yield ( |
| api.test("non_inclusive_word") |
| + try_build |
| + api.step_data( |
| "check commit tags.get change details", |
| api.json.output(non_inclusive_commit_message), |
| ) |
| + api.step_data( |
| "check for inclusivity.get change diff for path/to/file.md", |
| api.raw_io.stream_output_text(diff.format("path/to/file.md")), |
| ) |
| + api.step_data( |
| "check for inclusivity.read path/to/file.md", |
| api.file.read_text(file_contents), |
| ) |
| ) |