| # Copyright 2022 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 flagging large-scale changes (LSCs) that may impact downstream projects.""" |
| |
| import datetime |
| |
| from recipe_engine import post_process |
| |
| from PB.recipes.fuchsia.lsc_suggester import InputProperties |
| |
| PYTHON_VERSION_COMPATIBILITY = "PY3" |
| |
| DEPS = [ |
| "fuchsia/gerrit", |
| "fuchsia/status_check", |
| "recipe_engine/json", |
| "recipe_engine/properties", |
| "recipe_engine/url", |
| ] |
| |
| PROPERTIES = InputProperties |
| |
| FX_LSC_MESSAGE = """ |
| Please run `fx lsc presubmit` on API+1 changes. See http://go/run-fx-lsc-presubmit. |
| |
| Note that the LSC tryjobs are non-blocking. You will need to check the results manually. |
| """ |
| FX_LSC_TAG = "autogenerated:suggest-fx-lsc" |
| |
| |
| def RunSteps(api, props): |
| assert props.gerrit_host, "props.gerrit_host must be specified" |
| for change in get_eligible_changes_with_messages(api, props.gerrit_host): |
| # Only comment on the change if it has not been commented on before |
| # regardless of patchset. change["messages"] contains messages from all |
| # patchsets. |
| assert "messages" in change, "change %s must have a `messages` key" % change |
| has_fx_lsc_tag = any( |
| message.get("tag") == FX_LSC_TAG for message in change["messages"] |
| ) |
| if not has_fx_lsc_tag: |
| step = api.gerrit.set_review( |
| "add fx lsc message to %d" % change["_number"], |
| api.url.unquote(change["id"]), |
| message=FX_LSC_MESSAGE, |
| tag=FX_LSC_TAG, |
| notify="OWNER", |
| host=props.gerrit_host, |
| ) |
| |
| |
| def get_eligible_changes_with_messages(api, gerrit_host): |
| """Finds changes to suggest running fx lsc. |
| |
| Eligible changes have the following properties: |
| * unsubmitted |
| * recently modified/created |
| * need the API-Review label or have API+1 label |
| * in directory:sdk |
| |
| Args: |
| gerrit_host (str): Gerrit Host to query. |
| |
| Returns: |
| changes ([]json ChangeInfo): list of changes that are suggested to run |
| fx lsc. See |
| https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#change-info. |
| """ |
| # We restrict the results to recently modified/created changes. This is to |
| # avoid messaging abandoned changes so that we do not spam users. |
| # |
| # The following change fxr/644416 had 80 messages and the result size was |
| # ~52KB -> 100KB. We expect a max of O(10) eligible changes, where result |
| # size will be 1MB. |
| raw_query = "is:open -is:wip (label:Api-Review=need OR label:Api-Review+1) -age:1h directory:sdk" |
| # Query for unsubmitted changes that are api+1. Get the messages so that we |
| # can determine if the change has been fx lsc commented before. The query |
| # will get all the messages from all patchsets from a change. |
| changes = api.gerrit.change_query( |
| name="get eligible changes", |
| query_string=raw_query, |
| query_params=["MESSAGES"], |
| host=gerrit_host, |
| max_attempts=3, |
| timeout=datetime.timedelta(seconds=120), |
| ).json.output |
| |
| # API returns None if there is no search results instead of []. |
| return changes or [] |
| |
| |
| def GenTests(api): |
| # For this test, check that there are no fx lsc comments added. |
| yield api.status_check.test("empty") + api.properties( |
| gerrit_host="fuchsia-review.googlesource.com" |
| ) + api.step_data("get eligible changes", api.json.output([])) |
| # For this test, check that only change 1000 and 1001 got a fx lsc comment |
| # added. |
| yield api.status_check.test("default") + api.properties( |
| gerrit_host="fuchsia-review.googlesource.com" |
| ) + api.step_data( |
| "get eligible changes", |
| api.json.output( |
| [ |
| { |
| "id": "myProject~main~1000", |
| "project": "myProject", |
| "status": "NEW", |
| "_number": 1000, |
| "messages": [], |
| }, |
| { |
| "id": "myProject~main~1001", |
| "project": "myProject", |
| "status": "NEW", |
| "_number": 1001, |
| "messages": [ |
| {"message": ""}, |
| {"message": "nothing"}, |
| ], |
| }, |
| { |
| "id": "myProject~main~1002", |
| "project": "myProject", |
| "status": "NEW", |
| "_number": 1002, |
| "messages": [ |
| {"message": ""}, |
| {"message": FX_LSC_MESSAGE, "tag": FX_LSC_TAG}, |
| {"message": "nothing"}, |
| ], |
| }, |
| { |
| "id": "myProject~main~1003", |
| "project": "myProject", |
| "status": "NEW", |
| "_number": 1003, |
| "messages": [ |
| { |
| "message": "Different from current FX_LSC_MESSAGE", |
| "tag": FX_LSC_TAG, |
| }, |
| ], |
| }, |
| ] |
| ), |
| ) + api.post_process( |
| post_process.MustRun, "add fx lsc message to 1000", "add fx lsc message to 1001" |
| ) |