|
| 1 | +""" |
| 2 | +This script triggers .yamato/wrench/publish-trigger.yml#all_promotion_related_jobs_promotiontrigger to facilitate NGO release process |
| 3 | +We still need to manually set up Packageworks but this script will already trigger required jobs so we don't need to wait for them |
| 4 | +The goal is to already trigger those on Saturday when release branch is being created so on Monday we can already see the results |
| 5 | +
|
| 6 | +Additionally the job also triggers build automation job that will prepare builds for the Playtest. |
| 7 | +
|
| 8 | +Requirements: |
| 9 | +- A Long Lived Yamato API Token must be available as an environment variable. |
| 10 | +""" |
| 11 | +#!/usr/bin/env python3 |
| 12 | +import os |
| 13 | +import sys |
| 14 | +import requests |
| 15 | + |
| 16 | +UTILS_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '../Utils')) |
| 17 | +sys.path.insert(0, UTILS_DIR) |
| 18 | +from general_utils import get_package_version_from_manifest # nopep8 |
| 19 | +from git_utils import get_latest_git_revision # nopep8 |
| 20 | +from config import getPackageManifestPath, getNetcodeReleaseBranchName, getNetcodeProjectID # nopep8 |
| 21 | + |
| 22 | +YAMATO_API_URL = "https://yamato-api.cds.internal.unity3d.com/jobs" |
| 23 | + |
| 24 | +def trigger_wrench_promotion_job_on_yamato(yamato_api_token, project_id, branch_name, revision_sha): |
| 25 | + """ |
| 26 | + Triggers publish-trigger.yml#all_promotion_related_jobs_promotiontrigger job (via the REST API) to run release validation. |
| 27 | + This function basically query the job that NEEDS to pass in order to release via Packageworks |
| 28 | + Note that this will not publish/promote anything by itself but will just trigger the job that will run all the required tests and validations. |
| 29 | +
|
| 30 | + For the arguments we need to pass the Yamato API Long Lived Token, project ID, branch name and revision SHA on which we want to trigger the job. |
| 31 | + """ |
| 32 | + |
| 33 | + headers = { |
| 34 | + "Authorization": f"ApiKey {yamato_api_token}", |
| 35 | + "Content-Type": "application/json" |
| 36 | + } |
| 37 | + |
| 38 | + data = { |
| 39 | + "source": { |
| 40 | + "branchname": branch_name, |
| 41 | + "revision": revision_sha, |
| 42 | + }, |
| 43 | + "links": { |
| 44 | + "project": f"/projects/{project_id}", |
| 45 | + "jobDefinition": f"/projects/{project_id}/revisions/{revision_sha}/job-definitions/.yamato%2Fwrench%2Fpublish-trigger.yml%23all_promotion_related_jobs_promotiontrigger" |
| 46 | + } |
| 47 | + } |
| 48 | + |
| 49 | + print(f"Triggering job on branch {branch_name}...\n") |
| 50 | + response = requests.post(YAMATO_API_URL, headers=headers, json=data) |
| 51 | + |
| 52 | + if response.status_code in [200, 201]: |
| 53 | + data = response.json() |
| 54 | + print(f"Successfully triggered '{data['jobDefinitionName']}' where full path is '{data['jobDefinition']['filename']}' on {branch_name} branch and {revision_sha} revision.") |
| 55 | + else: |
| 56 | + print(f"Failed to trigger job. Status: {response.status_code}", file=sys.stderr) |
| 57 | + print("Error:", response.text, file=sys.stderr) |
| 58 | + sys.exit(1) |
| 59 | + |
| 60 | + |
| 61 | +def trigger_automated_builds_job_on_yamato(yamato_api_token, project_id, branch_name, revision_sha, samples_to_build, build_automation_configs): |
| 62 | + """ |
| 63 | + Triggers Yamato jobs (via the REST API) to prepare builds for Playtest. |
| 64 | + Build Automation is based on https://github.cds.internal.unity3d.com/unity/dots/pull/14314 |
| 65 | +
|
| 66 | + For the arguments we need to pass the Yamato API Long Lived Token, project ID, branch name and revision SHA on which we want to trigger the job. |
| 67 | + On top of that we should pass samples_to_build in format like |
| 68 | +
|
| 69 | + samples_to_build = [ |
| 70 | + { |
| 71 | + "name": "NetcodeSamples", |
| 72 | + "jobDefinition": f".yamato%2Fproject-builders%2Fproject-builders.yml%23build_NetcodeSamples_project", |
| 73 | + } |
| 74 | + ] |
| 75 | +
|
| 76 | + Note that "name" is just a human readable name of the sample (for debug message )and "jobDefinition" is the path to the job definition in the Yamato project. This path needs to be URL encoded, so for example / or # signs need to be replaced with %2F and %23 respectively. |
| 77 | +
|
| 78 | + You also need to pass build_automation_configs which will specify arguments for the build automation job. It should be in the following format: |
| 79 | +
|
| 80 | + build_automation_configs = [ |
| 81 | + { |
| 82 | + "job_name": "Build Sample for Windows with minimal supported editor (2022.3), burst ON, IL2CPP", |
| 83 | + "variables": [ |
| 84 | + { "key": "BURST_ON_OFF", "value": "on" }, |
| 85 | + { "key": "PLATFORM_WIN64_MAC_ANDROID", "value": "win64" }, |
| 86 | + { "key": "SCRIPTING_BACKEND_IL2CPP_MONO", "value": "il2cpp" }, |
| 87 | + { "key": "UNITY_VERSION", "value": "2022.3" } |
| 88 | + ] |
| 89 | + } |
| 90 | + ] |
| 91 | +
|
| 92 | + Again, note that the "job_name" is used for debug message and "variables" is a list of environment variables that will be passed to the job. Each variable should be a dictionary with "key" and "value" fields. |
| 93 | +
|
| 94 | + The function will trigger builds for each sample in samples_to_build with each configuration in build_automation_configs. |
| 95 | + """ |
| 96 | + |
| 97 | + headers = { |
| 98 | + "Authorization": f"ApiKey {yamato_api_token}", |
| 99 | + "Content-Type": "application/json" |
| 100 | + } |
| 101 | + |
| 102 | + for sample in samples_to_build: |
| 103 | + for config in build_automation_configs: |
| 104 | + data = { |
| 105 | + "source": { |
| 106 | + "branchname": branch_name, |
| 107 | + "revision": revision_sha, |
| 108 | + }, |
| 109 | + "links": { |
| 110 | + "project": f"/projects/{project_id}", |
| 111 | + "jobDefinition": f"/projects/{project_id}/revisions/{revision_sha}/job-definitions/{sample['jobDefinition']}" |
| 112 | + }, |
| 113 | + "environmentVariables": config["variables"] |
| 114 | + } |
| 115 | + |
| 116 | + print(f"Triggering the build of {sample['name']} with a configuration '{config['job_name']}' on branch {branch_name}...\n") |
| 117 | + response = requests.post(YAMATO_API_URL, headers=headers, json=data) |
| 118 | + |
| 119 | + if response.status_code in [200, 201]: |
| 120 | + print("The job was successfully triggered \n") |
| 121 | + else: |
| 122 | + print(f"Failed to trigger job. Status: {response.status_code}", file=sys.stderr) |
| 123 | + print(" Error:", response.text, file=sys.stderr) |
| 124 | + # I will continue the job since it has a limited amount of requests and I don't want to block the whole script if one of the jobs fails |
| 125 | + |
| 126 | + |
| 127 | + |
| 128 | +def trigger_NGO_release_preparation_jobs(): |
| 129 | + """Triggers Wrench dry run promotion josb and build automation for anticipation for Playtesting and Packageworks setup for NGO.""" |
| 130 | + |
| 131 | + samples_to_build = [ |
| 132 | + { |
| 133 | + "name": "BossRoom", |
| 134 | + "jobDefinition": f".yamato%2Fproject-builders%2Fproject-builders.yml%23build_BossRoom_project", |
| 135 | + }, |
| 136 | + { |
| 137 | + "name": "Asteroids", |
| 138 | + "jobDefinition": f".yamato%2Fproject-builders%2Fproject-builders.yml%23build_Asteroids_project", |
| 139 | + }, |
| 140 | + { |
| 141 | + "name": "SocialHub", |
| 142 | + "jobDefinition": f".yamato%2Fproject-builders%2Fproject-builders.yml%23build_SocialHub_project", |
| 143 | + } |
| 144 | + ] |
| 145 | + |
| 146 | + build_automation_configs = [ |
| 147 | + { |
| 148 | + "job_name": "Build Sample for Windows with minimal supported editor (2022.3), burst ON, IL2CPP", |
| 149 | + "variables": [ |
| 150 | + { "key": "BURST_ON_OFF", "value": "on" }, |
| 151 | + { "key": "PLATFORM_WIN64_MAC_ANDROID", "value": "win64" }, |
| 152 | + { "key": "SCRIPTING_BACKEND_IL2CPP_MONO", "value": "il2cpp" }, |
| 153 | + { "key": "UNITY_VERSION", "value": "2022.3" } # Minimal supported editor |
| 154 | + ] |
| 155 | + }, |
| 156 | + { |
| 157 | + "job_name": "Build Sample for Windows with latest functional editor (6000.2), burst ON, IL2CPP", |
| 158 | + "variables": [ |
| 159 | + { "key": "BURST_ON_OFF", "value": "on" }, |
| 160 | + { "key": "PLATFORM_WIN64_MAC_ANDROID", "value": "win64" }, |
| 161 | + { "key": "SCRIPTING_BACKEND_IL2CPP_MONO", "value": "il2cpp" }, |
| 162 | + { "key": "UNITY_VERSION", "value": "6000.2" } # Editor that most our users will use (not alpha). Sometimes when testing on trunk we have weird editor issues not caused by us so the preference will be to test on latest editor that our users will use. |
| 163 | + ] |
| 164 | + }, |
| 165 | + { |
| 166 | + "job_name": "Build Sample for Windows with latest editor (trunk), burst ON, IL2CPP", |
| 167 | + "variables": [ |
| 168 | + { "key": "BURST_ON_OFF", "value": "on" }, |
| 169 | + { "key": "PLATFORM_WIN64_MAC_ANDROID", "value": "win64" }, |
| 170 | + { "key": "SCRIPTING_BACKEND_IL2CPP_MONO", "value": "il2cpp" }, |
| 171 | + { "key": "UNITY_VERSION", "value": "trunk" } # latest editor |
| 172 | + ] |
| 173 | + }, |
| 174 | + { |
| 175 | + "job_name": "Build Sample for MacOS with minimal supported editor (2022.3), burst OFF, Mono", |
| 176 | + "variables": [ |
| 177 | + { "key": "BURST_ON_OFF", "value": "off" }, |
| 178 | + { "key": "PLATFORM_WIN64_MAC_ANDROID", "value": "mac" }, |
| 179 | + { "key": "SCRIPTING_BACKEND_IL2CPP_MONO", "value": "mono" }, |
| 180 | + { "key": "UNITY_VERSION", "value": "2022.3" } # Minimal supported editor |
| 181 | + ] |
| 182 | + }, |
| 183 | + { |
| 184 | + "job_name": "Build Sample for MacOS with latest functional editor (6000.2), burst OFF, Mono", |
| 185 | + "variables": [ |
| 186 | + { "key": "BURST_ON_OFF", "value": "off" }, |
| 187 | + { "key": "PLATFORM_WIN64_MAC_ANDROID", "value": "mac" }, |
| 188 | + { "key": "SCRIPTING_BACKEND_IL2CPP_MONO", "value": "mono" }, |
| 189 | + { "key": "UNITY_VERSION", "value": "6000.2" } # Editor that most our users will use (not alpha). Sometimes when testing on trunk we have weird editor issues not caused by us so the preference will be to test on latest editor that our users will use. |
| 190 | + ] |
| 191 | + }, |
| 192 | + { |
| 193 | + "job_name": "Build Sample for MacOS with latest editor (trunk), burst OFF, Mono", |
| 194 | + "variables": [ |
| 195 | + { "key": "BURST_ON_OFF", "value": "off" }, |
| 196 | + { "key": "PLATFORM_WIN64_MAC_ANDROID", "value": "mac" }, |
| 197 | + { "key": "SCRIPTING_BACKEND_IL2CPP_MONO", "value": "mono" }, |
| 198 | + { "key": "UNITY_VERSION", "value": "trunk" } # latest editor |
| 199 | + ] |
| 200 | + }, |
| 201 | + { |
| 202 | + "job_name": "Build Sample for Android with minimal supported editor (2022.3), burst ON, IL2CPP", |
| 203 | + "variables": [ |
| 204 | + { "key": "BURST_ON_OFF", "value": "on" }, |
| 205 | + { "key": "PLATFORM_WIN64_MAC_ANDROID", "value": "android" }, |
| 206 | + { "key": "SCRIPTING_BACKEND_IL2CPP_MONO", "value": "il2cpp" }, |
| 207 | + { "key": "UNITY_VERSION", "value": "2022.3" } # Minimal supported editor |
| 208 | + ] |
| 209 | + }, |
| 210 | + { |
| 211 | + "job_name": "Build Sample for Android with latest functional editor (6000.2), burst ON, IL2CPP", |
| 212 | + "variables": [ |
| 213 | + { "key": "BURST_ON_OFF", "value": "on" }, |
| 214 | + { "key": "PLATFORM_WIN64_MAC_ANDROID", "value": "android" }, |
| 215 | + { "key": "SCRIPTING_BACKEND_IL2CPP_MONO", "value": "il2cpp" }, |
| 216 | + { "key": "UNITY_VERSION", "value": "6000.2" } # Editor that most our users will use (not alpha). Sometimes when testing on trunk we have weird editor issues not caused by us so the preference will be to test on latest editor that our users will use. |
| 217 | + ] |
| 218 | + }, |
| 219 | + { |
| 220 | + "job_name": "Build Sample for Android with latest editor (trunk), burst ON, IL2CPP", |
| 221 | + "variables": [ |
| 222 | + { "key": "BURST_ON_OFF", "value": "on" }, |
| 223 | + { "key": "PLATFORM_WIN64_MAC_ANDROID", "value": "android" }, |
| 224 | + { "key": "SCRIPTING_BACKEND_IL2CPP_MONO", "value": "il2cpp" }, |
| 225 | + { "key": "UNITY_VERSION", "value": "trunk" } # latest editor |
| 226 | + ] |
| 227 | + } |
| 228 | + ] |
| 229 | + |
| 230 | + ngo_manifest_path = getPackageManifestPath() |
| 231 | + ngo_package_version = get_package_version_from_manifest(ngo_manifest_path) |
| 232 | + ngo_release_branch_name = getNetcodeReleaseBranchName(ngo_package_version) |
| 233 | + ngo_yamato_api_token = os.environ.get("NETCODE_YAMATO_API_KEY") |
| 234 | + |
| 235 | + ngo_project_ID = getNetcodeProjectID() |
| 236 | + revision_sha = get_latest_git_revision(ngo_release_branch_name) |
| 237 | + |
| 238 | + if not os.path.exists(ngo_manifest_path): |
| 239 | + print(f" Path does not exist: {ngo_manifest_path}") |
| 240 | + sys.exit(1) |
| 241 | + |
| 242 | + if ngo_package_version is None: |
| 243 | + print(f"Package version not found at {ngo_manifest_path}") |
| 244 | + sys.exit(1) |
| 245 | + |
| 246 | + if not ngo_yamato_api_token: |
| 247 | + print("Error: NETCODE_YAMATO_API_KEY environment variable not set.", file=sys.stderr) |
| 248 | + sys.exit(1) |
| 249 | + |
| 250 | + trigger_wrench_promotion_job_on_yamato(ngo_yamato_api_token, ngo_project_ID, ngo_release_branch_name, revision_sha) |
| 251 | + trigger_automated_builds_job_on_yamato(ngo_yamato_api_token, ngo_project_ID, ngo_release_branch_name, revision_sha, samples_to_build, build_automation_configs) |
| 252 | + |
| 253 | + |
| 254 | + |
| 255 | +if __name__ == "__main__": |
| 256 | + trigger_NGO_release_preparation_jobs() |
0 commit comments