Adds a results reporting module.
This module will be used to send build results data from dart-internal
to the flutter-dashboard.
Bug: https://github.com/flutter/flutter/issues/115490
Change-Id: I2beab566ba9970f14b3c352111f9c62adde72b68
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/36640
Reviewed-by: Yusuf Mohsinally <mohsinally@google.com>
Commit-Queue: Godofredo Contreras <godofredoc@google.com>
diff --git a/recipe_modules/status_reporting/__init__.py b/recipe_modules/status_reporting/__init__.py
new file mode 100644
index 0000000..b37189a
--- /dev/null
+++ b/recipe_modules/status_reporting/__init__.py
@@ -0,0 +1,10 @@
+# Copyright 2022 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+DEPS = [
+ 'fuchsia/gcloud',
+ 'recipe_engine/file',
+ 'recipe_engine/step',
+]
diff --git a/recipe_modules/status_reporting/api.py b/recipe_modules/status_reporting/api.py
new file mode 100644
index 0000000..7953045
--- /dev/null
+++ b/recipe_modules/status_reporting/api.py
@@ -0,0 +1,43 @@
+# Copyright 2022 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+from recipe_engine import recipe_api
+from google.protobuf import json_format
+
+from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb2
+from PB.go.chromium.org.luci.buildbucket.proto import build as build_pb2
+
+
+class StatusReportingApi(recipe_api.RecipeApi):
+
+ def build_to_json(self, build):
+ """Encodes a shard_util_v2.SubbuildResult to a json string.
+
+ Args:
+ build(build.Build): The build to encode.
+
+ Returns:
+ A string with the Build message encoded as Json.
+ """
+ return json_format.MessageToJson(build)
+
+ def publish_builds(
+ self,
+ subbuilds,
+ topic='projects/flutter-dashboard/topics/luci-builds-prod'):
+ """Publish builds to a pubsub topic.
+
+ Args:
+ subbuilds(dict): A dictionary with the build name as key and a value
+ of shard_util_v2.SubbuildResult as a value.
+ topic(str): (optional) gcloud topic to publish message to.
+ """
+ with self.m.step.nest('Publish results') as presentation:
+ for id_name, build in subbuilds.items():
+ cmd = [
+ 'pubsub', 'topics', 'publish', topic,
+ '--message=\'%s\'' % self.build_to_json(build.build_proto)
+ ]
+ self.m.gcloud(*cmd, infra_step=True)
diff --git a/recipe_modules/status_reporting/examples/full.expected/basic.json b/recipe_modules/status_reporting/examples/full.expected/basic.json
new file mode 100644
index 0000000..4b7ec7a
--- /dev/null
+++ b/recipe_modules/status_reporting/examples/full.expected/basic.json
@@ -0,0 +1,109 @@
+[
+ {
+ "cmd": [],
+ "name": "Publish results"
+ },
+ {
+ "cmd": [],
+ "name": "Publish results.ensure gcloud",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "RECIPE_MODULE[fuchsia::gcloud]/resources/tool_manifest.json",
+ "/path/to/tmp/json"
+ ],
+ "infra_step": true,
+ "name": "Publish results.ensure gcloud.read manifest",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@tool_manifest.json@{@@@",
+ "@@@STEP_LOG_LINE@tool_manifest.json@ \"path\": \"path/to/gcloud\",@@@",
+ "@@@STEP_LOG_LINE@tool_manifest.json@ \"version\": \"version:pinned-version\"@@@",
+ "@@@STEP_LOG_LINE@tool_manifest.json@}@@@",
+ "@@@STEP_LOG_END@tool_manifest.json@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "Publish results.ensure gcloud.install path/to/gcloud",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "ensure-directory",
+ "--mode",
+ "0777",
+ "[START_DIR]/cipd_tool/path/to/gcloud/version%3Apinned-version"
+ ],
+ "infra_step": true,
+ "name": "Publish results.ensure gcloud.install path/to/gcloud.ensure package directory",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@3@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "cipd",
+ "ensure",
+ "-root",
+ "[START_DIR]/cipd_tool/path/to/gcloud/version%3Apinned-version",
+ "-ensure-file",
+ "path/to/gcloud version:pinned-version",
+ "-max-threads",
+ "0",
+ "-json-output",
+ "/path/to/tmp/json"
+ ],
+ "infra_step": true,
+ "name": "Publish results.ensure gcloud.install path/to/gcloud.ensure_installed",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@3@@@",
+ "@@@STEP_LOG_LINE@json.output@{@@@",
+ "@@@STEP_LOG_LINE@json.output@ \"result\": {@@@",
+ "@@@STEP_LOG_LINE@json.output@ \"\": [@@@",
+ "@@@STEP_LOG_LINE@json.output@ {@@@",
+ "@@@STEP_LOG_LINE@json.output@ \"instance_id\": \"resolved-instance_id-of-version:pinned-v\", @@@",
+ "@@@STEP_LOG_LINE@json.output@ \"package\": \"path/to/gcloud\"@@@",
+ "@@@STEP_LOG_LINE@json.output@ }@@@",
+ "@@@STEP_LOG_LINE@json.output@ ]@@@",
+ "@@@STEP_LOG_LINE@json.output@ }@@@",
+ "@@@STEP_LOG_LINE@json.output@}@@@",
+ "@@@STEP_LOG_END@json.output@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python",
+ "[START_DIR]/cipd_tool/path/to/gcloud/version%3Apinned-version/lib/gcloud.py",
+ "pubsub",
+ "topics",
+ "publish",
+ "projects/flutter-dashboard/topics/luci-builds-prod",
+ "--message='{\n \"builder\": {\n \"project\": \"flutter\",\n \"bucket\": \"try\",\n \"builder\": \"mybuild\"\n }\n}'"
+ ],
+ "infra_step": true,
+ "name": "Publish results.gcloud pubsub",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "name": "$result"
+ }
+]
\ No newline at end of file
diff --git a/recipe_modules/status_reporting/examples/full.py b/recipe_modules/status_reporting/examples/full.py
new file mode 100644
index 0000000..d7ccf56
--- /dev/null
+++ b/recipe_modules/status_reporting/examples/full.py
@@ -0,0 +1,27 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from recipe_engine.post_process import DoesNotRun, Filter, StatusFailure
+
+from PB.go.chromium.org.luci.buildbucket.proto import build as build_pb2
+from PB.go.chromium.org.luci.buildbucket.proto import builder_common as builder_pb2
+from RECIPE_MODULES.flutter.shard_util_v2.api import SubbuildResult
+
+
+DEPS = [
+ 'flutter/status_reporting'
+]
+
+def RunSteps(api):
+ build = build_pb2.Build(
+ builder=builder_pb2.BuilderID(project='flutter', bucket='try', builder='mybuild')
+ )
+ result = SubbuildResult(
+ builder='mybuild', build_id=123, build_name='build_name',
+ url='https://123', build_proto=build)
+ api.status_reporting.publish_builds({'mybuild': result})
+
+
+def GenTests(api):
+ yield api.test('basic')
diff --git a/recipe_modules/status_reporting/resources/mac_result.json b/recipe_modules/status_reporting/resources/mac_result.json
new file mode 100644
index 0000000..fd6ec9e
--- /dev/null
+++ b/recipe_modules/status_reporting/resources/mac_result.json
@@ -0,0 +1,42 @@
+{
+ "build": {
+ "bucket": "luci.flutter.prod",
+ "canary": false,
+ "canary_preference": "PROD",
+ "completed_ts": "1669080231756573",
+ "created_by": "user:flutter-dashboard@appspot.gserviceaccount.com",
+ "created_ts": "1669079440844500",
+ "experimental": false,
+ "id": "8796837072196031249",
+ "parameters_json": "{\"builder_name\": \"Mac iOS Engine Release\", \"properties\": {\"$flutter/osx_sdk\": {\"sdk_version\": \"14a5294e\"}, \"bringup\": false, \"build_android_aot\": false, \"build_android_debug\": false, \"build_android_jit_release\": false, \"build_android_vulkan\": false, \"build_fuchsia\": false, \"build_host\": false, \"build_ios\": true, \"cpu\": \"x86\", \"dependencies\": [{\"dependency\": \"open_jdk\", \"version\": \"version:1.8.0u202-b08\"}], \"device_type\": \"none\", \"exe_cipd_version\": \"refs/heads/main\", \"gcs_goldens_bucket\": \"\", \"git_branch\": \"main\", \"ios_debug\": false, \"ios_profile\": false, \"ios_release\": true, \"jazzy_version\": \"0.14.1\", \"no_bitcode\": false, \"os\": \"Mac-12\", \"xcode\": \"14a5294e\"}}",
+ "project": "flutter",
+ "result": "SUCCESS",
+ "result_details_json": "{\"properties\": {\"got_engine_revision\": \"8dd8e092e43f1c3051239f0cf2b01e8caeca6b49\"}, \"swarming\": {\"bot_dimensions\": {\"bot_config\": [\"bot_config.py\"], \"caches\": [\"engine__builder\", \"engine__open_jdk_version_1_8_0u202_b08_legacy\", \"engine__xcode_14a5294e_legacy\", \"engine_main_builder\", \"engine_main_open_jdk_version_1_8_0u202_b08_legacy\", \"engine_main_xcode_14a5294e_legacy\", \"flutter_3_3_0_android_sdk_version_32v1_legacy\", \"flutter_3_3_0_open_jdk_11_legacy\", \"flutter__android_sdk_version_33v6_legacy\", \"flutter__chrome_and_driver_version_98_1_legacy\", \"flutter__open_jdk_version_11_legacy\", \"flutter__xcode_14a5294e_legacy\", \"git\", \"goma_v2\", \"plugins_main_xcode_14a5294e_legacy\", \"vpython\"], \"cores\": [\"12\"], \"cpu\": [\"x86\", \"x86-64\", \"x86-64-i7-8700B\"], \"device_os\": [\"none\"], \"device_type\": [\"none\"], \"display_attached\": [\"1\"], \"dut_state\": [\"ready\"], \"gce\": [\"0\"], \"gpu\": [\"8086\", \"8086:3e9b\"], \"hidpi\": [\"0\"], \"id\": [\"build805-m9\"], \"inside_docker\": [\"0\"], \"mac_model\": [\"Macmini8,1\"], \"machine_type\": [\"n1-standard-8\"], \"os\": [\"Mac\", \"Mac-12\", \"Mac-12.6\", \"Mac-12.6-21G115\"], \"pool\": [\"luci.flutter.prod\"], \"python\": [\"3\", \"3.8\", \"3.8.10+chromium.23\"], \"server_version\": [\"6898-ae55986\"], \"ssd\": [\"1\"], \"ufs_state\": [\"ready\"], \"ufs_zone\": [\"ZONE_ATL97\"], \"zone\": [\"us\", \"us-atl\", \"us-atl-golo\", \"us-atl-golo-m9\"]}}}",
+ "retry_of": "0",
+ "service_account": "flutter-prod-builder@chops-service-accounts.iam.gserviceaccount.com",
+ "started_ts": "1669079478114499",
+ "status": "COMPLETED",
+ "status_changed_ts": "1669080231756574",
+ "tags": [
+ "build_address:luci.flutter.prod/Mac iOS Engine Release/17453",
+ "builder:Mac iOS Engine Release",
+ "buildset:commit/git/8dd8e092e43f1c3051239f0cf2b01e8caeca6b49",
+ "buildset:commit/gitiles/flutter.googlesource.com/mirrors/engine/+/8dd8e092e43f1c3051239f0cf2b01e8caeca6b49",
+ "gitiles_ref:refs/heads/main",
+ "scheduler_job_id:flutter/Mac iOS Engine Release",
+ "swarming_hostname:chromium-swarm.appspot.com",
+ "swarming_tag:log_location:logdog://logs.chromium.org/flutter/buildbucket/cr-buildbucket/8796837072196031249/+/annotations",
+ "swarming_tag:luci_project:flutter",
+ "swarming_tag:os:Mac",
+ "swarming_tag:recipe_name:engine/engine",
+ "swarming_tag:recipe_package:flutter/recipe_bundles/flutter.googlesource.com/recipes",
+ "swarming_task_id:5eb5b4cc3bbbfe10",
+ "user_agent:flutter-cocoon"
+ ],
+ "updated_ts": "1669080231756573",
+ "url": "https://ci.chromium.org/b/8796837072196031249",
+ "utcnow_ts": "1669080231879293"
+ },
+ "hostname": "cr-buildbucket.appspot.com",
+ "user_data": "eyJjb21taXRfa2V5IjoiZmx1dHRlci9lbmdpbmUvbWFpbi84ZGQ4ZTA5MmU0M2YxYzMwNTEyMzlmMGNmMmIwMWU4Y2FlY2E2YjQ5IiwidGFza19rZXkiOiI1ODE1Njg2NTQ3NzY3Mjk2In0="
+}
diff --git a/recipe_modules/status_reporting/resources/mac_result2.json b/recipe_modules/status_reporting/resources/mac_result2.json
new file mode 100644
index 0000000..fd6ec9e
--- /dev/null
+++ b/recipe_modules/status_reporting/resources/mac_result2.json
@@ -0,0 +1,42 @@
+{
+ "build": {
+ "bucket": "luci.flutter.prod",
+ "canary": false,
+ "canary_preference": "PROD",
+ "completed_ts": "1669080231756573",
+ "created_by": "user:flutter-dashboard@appspot.gserviceaccount.com",
+ "created_ts": "1669079440844500",
+ "experimental": false,
+ "id": "8796837072196031249",
+ "parameters_json": "{\"builder_name\": \"Mac iOS Engine Release\", \"properties\": {\"$flutter/osx_sdk\": {\"sdk_version\": \"14a5294e\"}, \"bringup\": false, \"build_android_aot\": false, \"build_android_debug\": false, \"build_android_jit_release\": false, \"build_android_vulkan\": false, \"build_fuchsia\": false, \"build_host\": false, \"build_ios\": true, \"cpu\": \"x86\", \"dependencies\": [{\"dependency\": \"open_jdk\", \"version\": \"version:1.8.0u202-b08\"}], \"device_type\": \"none\", \"exe_cipd_version\": \"refs/heads/main\", \"gcs_goldens_bucket\": \"\", \"git_branch\": \"main\", \"ios_debug\": false, \"ios_profile\": false, \"ios_release\": true, \"jazzy_version\": \"0.14.1\", \"no_bitcode\": false, \"os\": \"Mac-12\", \"xcode\": \"14a5294e\"}}",
+ "project": "flutter",
+ "result": "SUCCESS",
+ "result_details_json": "{\"properties\": {\"got_engine_revision\": \"8dd8e092e43f1c3051239f0cf2b01e8caeca6b49\"}, \"swarming\": {\"bot_dimensions\": {\"bot_config\": [\"bot_config.py\"], \"caches\": [\"engine__builder\", \"engine__open_jdk_version_1_8_0u202_b08_legacy\", \"engine__xcode_14a5294e_legacy\", \"engine_main_builder\", \"engine_main_open_jdk_version_1_8_0u202_b08_legacy\", \"engine_main_xcode_14a5294e_legacy\", \"flutter_3_3_0_android_sdk_version_32v1_legacy\", \"flutter_3_3_0_open_jdk_11_legacy\", \"flutter__android_sdk_version_33v6_legacy\", \"flutter__chrome_and_driver_version_98_1_legacy\", \"flutter__open_jdk_version_11_legacy\", \"flutter__xcode_14a5294e_legacy\", \"git\", \"goma_v2\", \"plugins_main_xcode_14a5294e_legacy\", \"vpython\"], \"cores\": [\"12\"], \"cpu\": [\"x86\", \"x86-64\", \"x86-64-i7-8700B\"], \"device_os\": [\"none\"], \"device_type\": [\"none\"], \"display_attached\": [\"1\"], \"dut_state\": [\"ready\"], \"gce\": [\"0\"], \"gpu\": [\"8086\", \"8086:3e9b\"], \"hidpi\": [\"0\"], \"id\": [\"build805-m9\"], \"inside_docker\": [\"0\"], \"mac_model\": [\"Macmini8,1\"], \"machine_type\": [\"n1-standard-8\"], \"os\": [\"Mac\", \"Mac-12\", \"Mac-12.6\", \"Mac-12.6-21G115\"], \"pool\": [\"luci.flutter.prod\"], \"python\": [\"3\", \"3.8\", \"3.8.10+chromium.23\"], \"server_version\": [\"6898-ae55986\"], \"ssd\": [\"1\"], \"ufs_state\": [\"ready\"], \"ufs_zone\": [\"ZONE_ATL97\"], \"zone\": [\"us\", \"us-atl\", \"us-atl-golo\", \"us-atl-golo-m9\"]}}}",
+ "retry_of": "0",
+ "service_account": "flutter-prod-builder@chops-service-accounts.iam.gserviceaccount.com",
+ "started_ts": "1669079478114499",
+ "status": "COMPLETED",
+ "status_changed_ts": "1669080231756574",
+ "tags": [
+ "build_address:luci.flutter.prod/Mac iOS Engine Release/17453",
+ "builder:Mac iOS Engine Release",
+ "buildset:commit/git/8dd8e092e43f1c3051239f0cf2b01e8caeca6b49",
+ "buildset:commit/gitiles/flutter.googlesource.com/mirrors/engine/+/8dd8e092e43f1c3051239f0cf2b01e8caeca6b49",
+ "gitiles_ref:refs/heads/main",
+ "scheduler_job_id:flutter/Mac iOS Engine Release",
+ "swarming_hostname:chromium-swarm.appspot.com",
+ "swarming_tag:log_location:logdog://logs.chromium.org/flutter/buildbucket/cr-buildbucket/8796837072196031249/+/annotations",
+ "swarming_tag:luci_project:flutter",
+ "swarming_tag:os:Mac",
+ "swarming_tag:recipe_name:engine/engine",
+ "swarming_tag:recipe_package:flutter/recipe_bundles/flutter.googlesource.com/recipes",
+ "swarming_task_id:5eb5b4cc3bbbfe10",
+ "user_agent:flutter-cocoon"
+ ],
+ "updated_ts": "1669080231756573",
+ "url": "https://ci.chromium.org/b/8796837072196031249",
+ "utcnow_ts": "1669080231879293"
+ },
+ "hostname": "cr-buildbucket.appspot.com",
+ "user_data": "eyJjb21taXRfa2V5IjoiZmx1dHRlci9lbmdpbmUvbWFpbi84ZGQ4ZTA5MmU0M2YxYzMwNTEyMzlmMGNmMmIwMWU4Y2FlY2E2YjQ5IiwidGFza19rZXkiOiI1ODE1Njg2NTQ3NzY3Mjk2In0="
+}