recipe to run for codesign

tested through `led get-builder 'luci.flutter.prod:Mac device_doctor' > /tmp/test.json`, and `cat /tmp/test.json |  led edit-recipe-bundle | led launch`. test link is https://ci.chromium.org/raw/build/logs.chromium.org/flutter/led/xilaizhang_google.com/ca661824e4debd72dcfab48ba84dd1bf1ab2bab8345d345418f227ba70ca9bae/+/build.proto?server=chromium-swarm.appspot.com.

the cipd can be viewed at https://chrome-infra-packages.appspot.com/p/flutter/codesign.

Change-Id: I5352ec19c4bce8ec7c0db737bf4af871f9f3542e
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/31240
Reviewed-by: Keyong Han <keyonghan@google.com>
Commit-Queue: Xilai Zhang <xilaizhang@google.com>
Reviewed-by: Casey Hillers <chillers@google.com>
diff --git a/recipes/cocoon/cipd.expected/cipd_mac.json b/recipes/cocoon/cipd.expected/cipd_mac.json
new file mode 100644
index 0000000..3ac099f
--- /dev/null
+++ b/recipes/cocoon/cipd.expected/cipd_mac.json
@@ -0,0 +1,172 @@
+[
+  {
+    "cmd": [],
+    "name": "Checkout flutter/cocoon"
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+      "--path",
+      "[START_DIR]/cocoon",
+      "--url",
+      "https://flutter.googlesource.com/mirrors/cocoon"
+    ],
+    "name": "Checkout flutter/cocoon.git setup",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "origin",
+      "main",
+      "--recurse-submodules",
+      "--progress",
+      "--tags"
+    ],
+    "cwd": "[START_DIR]/cocoon",
+    "env": {
+      "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+    },
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.git fetch",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "FETCH_HEAD"
+    ],
+    "cwd": "[START_DIR]/cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.git checkout",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[START_DIR]/cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.read revision",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[START_DIR]/cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.git clean",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "sync"
+    ],
+    "cwd": "[START_DIR]/cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.submodule sync",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "update",
+      "--init",
+      "--recursive"
+    ],
+    "cwd": "[START_DIR]/cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.submodule update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "bash",
+      "[START_DIR]/cocoon/codesign/tool/build.sh"
+    ],
+    "cwd": "[START_DIR]/cocoon/codesign",
+    "name": "build package"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "pkg-build",
+      "-in",
+      "[START_DIR]/cocoon/codesign/build",
+      "-name",
+      "flutter/codesign/mac-amd64",
+      "-out",
+      "codesign.zip",
+      "-hash-algo",
+      "sha256",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "cwd": "[START_DIR]/cocoon/codesign",
+    "name": "build mac-amd64",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"instance_id\": \"40-chars-fake-of-the-package-instance_id\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"package\": \"flutter/codesign/mac-amd64\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "pkg-register",
+      "codesign.zip",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "cwd": "[START_DIR]/cocoon/codesign",
+    "name": "register flutter/codesign/mac-amd64",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"instance_id\": \"40-chars-fake-of-the-package-instance_id\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"package\": \"flutter/codesign/mac-amd64\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LINK@flutter/codesign/mac-amd64@https://chrome-infra-packages.appspot.com/p/flutter/codesign/mac-amd64/+/40-chars-fake-of-the-package-instance_id@@@"
+    ]
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipes/cocoon/cipd.expected/cipd_win.json b/recipes/cocoon/cipd.expected/cipd_win.json
new file mode 100644
index 0000000..e0d8668
--- /dev/null
+++ b/recipes/cocoon/cipd.expected/cipd_win.json
@@ -0,0 +1,171 @@
+[
+  {
+    "cmd": [],
+    "name": "Checkout flutter/cocoon"
+  },
+  {
+    "cmd": [
+      "python3",
+      "-u",
+      "RECIPE_MODULE[depot_tools::git]\\resources\\git_setup.py",
+      "--path",
+      "[START_DIR]\\cocoon",
+      "--url",
+      "https://flutter.googlesource.com/mirrors/cocoon"
+    ],
+    "name": "Checkout flutter/cocoon.git setup",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "origin",
+      "main",
+      "--recurse-submodules",
+      "--progress",
+      "--tags"
+    ],
+    "cwd": "[START_DIR]\\cocoon",
+    "env": {
+      "PATH": "RECIPE_REPO[depot_tools];<PATH>"
+    },
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.git fetch",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "FETCH_HEAD"
+    ],
+    "cwd": "[START_DIR]\\cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.git checkout",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[START_DIR]\\cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.read revision",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+      "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[START_DIR]\\cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.git clean",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "sync"
+    ],
+    "cwd": "[START_DIR]\\cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.submodule sync",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "submodule",
+      "update",
+      "--init",
+      "--recursive"
+    ],
+    "cwd": "[START_DIR]\\cocoon",
+    "infra_step": true,
+    "name": "Checkout flutter/cocoon.submodule update",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]\\cocoon\\device_doctor\\tool\\build.bat"
+    ],
+    "cwd": "[START_DIR]\\cocoon\\device_doctor",
+    "name": "build package"
+  },
+  {
+    "cmd": [
+      "cipd.bat",
+      "pkg-build",
+      "-in",
+      "[START_DIR]\\cocoon\\device_doctor\\build",
+      "-name",
+      "flutter/device_doctor/windows-amd64",
+      "-out",
+      "device_doctor.zip",
+      "-hash-algo",
+      "sha256",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "cwd": "[START_DIR]\\cocoon\\device_doctor",
+    "name": "build windows-amd64",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"instance_id\": \"40-chars-fake-of-the-package-instance_id\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"package\": \"flutter/device_doctor/windows-amd64\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd.bat",
+      "pkg-register",
+      "device_doctor.zip",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "cwd": "[START_DIR]\\cocoon\\device_doctor",
+    "name": "register flutter/device_doctor/windows-amd64",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"instance_id\": \"40-chars-fake-of-the-package-instance_id\", @@@",
+      "@@@STEP_LOG_LINE@json.output@    \"package\": \"flutter/device_doctor/windows-amd64\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LINK@flutter/device_doctor/windows-amd64@https://chrome-infra-packages.appspot.com/p/flutter/device_doctor/windows-amd64/+/40-chars-fake-of-the-package-instance_id@@@"
+    ]
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipes/cocoon/cipd.py b/recipes/cocoon/cipd.py
new file mode 100644
index 0000000..536ed36
--- /dev/null
+++ b/recipes/cocoon/cipd.py
@@ -0,0 +1,81 @@
+# 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 platform import platform
+from recipe_engine.recipe_api import Property
+
+PYTHON_VERSION_COMPATIBILITY = 'PY3'
+
+DEPS = [
+    'flutter/repo_util',
+    'flutter/yaml',
+    'recipe_engine/cipd',
+    'recipe_engine/context',
+    'recipe_engine/json',
+    'recipe_engine/path',
+    'recipe_engine/platform',
+    'recipe_engine/properties',
+    'recipe_engine/step',
+]
+
+
+# This recipe builds the codesign CIPD package.
+def RunSteps(api):
+  start_path = api.path['start_dir']
+  cocoon_dir = start_path.join('cocoon')
+  cocoon_git_rev = api.repo_util.checkout(
+      'cocoon',
+      cocoon_dir,
+      ref='refs/heads/main',
+  )
+
+  # Get properties from ci.yaml.
+  # Assume ci.yaml has the following properties
+  #   - name: Mac codesign
+  #     bringup: true
+  #     postsubmit: false
+  #     recipe: cocoon/codesign
+  #     properties:
+  #       add_recipes_cq: "true"
+  #     script: device_doctor/tool/build.sh
+  #     cipd_name: flutter/device_doctor/mac-amd64
+
+  script_path_list = api.properties.get('script')
+  cipd_full_name = api.properties.get('cipd_name')
+  project_name = cipd_full_name.split('/')[1]
+  project_path = cocoon_dir.join(project_name)
+
+  build_file = cocoon_dir.join(script_path_list)
+
+  cmd = [build_file]
+  if not api.platform.is_win:
+    cmd = ['bash', build_file]
+
+  with api.context(cwd=project_path):
+    api.step('build package', cmd)
+
+    cipd_zip_path = project_name + '.zip'
+
+    api.cipd.build(project_path.join('build'), cipd_zip_path, cipd_full_name)
+    api.cipd.register(cipd_full_name, cipd_zip_path)
+
+
+def GenTests(api):
+  yield api.test(
+      'cipd_mac',
+      api.properties(
+          script='codesign/tool/build.sh',
+          cipd_name='flutter/codesign/mac-amd64'
+      ),
+      api.platform('mac', 64),
+  )
+
+  yield api.test(
+      'cipd_win',
+      api.properties(
+          script='device_doctor\\tool\\build.bat',
+          cipd_name='flutter/device_doctor/windows-amd64'
+      ),
+      api.platform('win', 64),
+  )