Skip to content

Commit 830aac6

Browse files
TECH_DEBT: Add QA2 support and fix full commit hash resolution in get_deployed_commit.py (#1843)
* TECH_DEBT: Add QA2 environment support to get_deployed_commit.py The Deploy_All_Services pipeline has offered scale-qa2 as an environment since 82f073a, but get_deployed_commit.py only recognized dev-scale, scale-test and scale-qa. Selecting QA2 failed the Summarize job with "Unknown environment 'scale-qa2'", which skipped the dependent Deploy job. - Map scale-qa2 to a QA2_BASE_URL environment variable, alongside the existing three - List scale-qa2 in the unknown-environment and empty-BASE_URL error messages - Document scale-qa2 in the script docstring and the Scripts/README.md row - Mention QA2 in the pipeline's environment parameter displayName Verified by running the script against scale-qa2 with QA2_BASE_URL set to https://qa2-admin.nhsnlink.org, which resolved the deployed commit 78b98b4 from /api/info. Unknown environments and the direct https:// URL argument are unchanged. Requires a QA2_BASE_URL variable to be added in Azure DevOps wherever QA_BASE_URL is already defined; without it the script reports the empty-BASE_URL error rather than querying the wrong host. * TECH_DEBT: Resolve short commit hashes via the GitHub commits API get_deployed_commit.py read the full SHA from payload.commit.sha2 in the JSON served by the GitHub commit page. That path no longer exists — the SHA moved to payload.commitRoute.commit.oid — so the chained .get() calls fell back to the short hash and returned it without raising. The "Attempting to translate..." line was therefore followed by neither a warning nor a translation. FromCommit then reached list-deploy-changes.py as a 7-character hash. It fetches both refs with 'git fetch --depth=1 origin <ref>', which GitHub rejects for anything but a full SHA ("couldn't find remote ref"), and that fetch discards stderr and ignores its exit code, so the deployment summary could silently come out empty. - Query api.github.com/repos/.../commits/<sha> with the 'application/vnd.github.sha' media type, which returns the 40-character hash as plain text, instead of reading the commit page's undocumented JSON payload - Accept the result only when it is exactly 40 characters, warning with the response body otherwise - Warn explicitly when FromCommit is still a short hash, naming the fetch that will fail, so a future breakage is not silent Verified against qa and qa2: 78b98b4 now resolves to 78b98b4. An unknown hash returns HTTP 422, which raises into the existing handler and then trips the short-hash warning. * TECH_DEBT: Bound the HTTP calls in get_deployed_commit.py with a timeout Neither urlopen call passed a timeout, and the script never sets a global socket default, so both used urlopen's default of blocking indefinitely. An unresponsive /api/info endpoint or GitHub API would hang the Summarize job until the Azure DevOps job timeout killed it, rather than failing the step with a usable error. - Add an HTTP_TIMEOUT_SECONDS constant of 30 seconds - Pass it to the /api/info request and the GitHub commits request, so both share the same budget A timeout on the /api/info call raises into the existing handler and exits through fail(); a timeout while resolving the full hash prints the existing warnings and leaves FromCommit as the short hash. Verified against qa2 that the normal path is unaffected: 78b98b4 still resolves to 78b98b4. * TECH_DEBT: Fail get_deployed_commit.py when the full hash cannot be resolved The script warned about an unresolved short hash and then published it anyway. The downstream consumer cannot use it: list-deploy-changes.py fetches both refs with 'git fetch --depth=1 origin <ref>', GitHub rejects unadvertised objects by short SHA, and that fetch discards stderr and ignores its exit code — so the deployment summary came out empty with nothing in the log to explain it. - Replace the short-hash warning with a fail(), reporting the same context on stderr and exiting nonzero - Place it ahead of the FromCommit print and the ##vso[task.setvariable] line, so no unusable value is published This makes the Summarize job fail whenever the GitHub lookup fails for any reason, including a rate limit or transport error, and Deploy is gated on Summarize succeeding. Verified against qa2 that the normal path is unchanged and exits 0. Forced the failure path with an unreachable API host: the warning and the ERROR line are both printed, the exit status is 1, and neither FromCommit nor the ##vso line is emitted.
1 parent f13092b commit 830aac6

3 files changed

Lines changed: 35 additions & 14 deletions

File tree

Azure_Pipelines/_deploy_all_services.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pool:
99

1010
parameters:
1111
- name: environment
12-
displayName: Which environment is this for? (DEV | TEST | QA)
12+
displayName: Which environment is this for? (DEV | TEST | QA | QA2)
1313
type: string
1414
values:
1515
- dev-scale

Scripts/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ subfolder and is summarised at the end.
3434
| `set_kubernetes_services.bat <namespace> <registry> <image>` | Points a Kubernetes namespace at a registry and image. |
3535
| `aca-container-statuses.ps1` | Lists Azure Container App running state and replica bounds. |
3636
| `aca-logs.bat <container> rep\|rev <id>` | Tails Container App logs for a replica or revision. |
37-
| `get_deployed_commit.py <environment>` | Reports the commit currently deployed to `dev-scale`, `scale-test` or `scale-qa`. |
37+
| `get_deployed_commit.py <environment>` | Reports the commit currently deployed to `dev-scale`, `scale-test`, `scale-qa` or `scale-qa2`. |
3838
| `list-deploy-changes.py <from> <to>` | Lists the deployment-relevant changes between two git refs. |
3939
| `upload_to_share.py` | Uploads a directory to an Azure File Share. |
4040

Scripts/get_deployed_commit.py

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
python3 scripts/get_deployed_commit.py <environment>
77
88
Arguments:
9-
environment: One of dev-scale | scale-test | scale-qa
9+
environment: One of dev-scale | scale-test | scale-qa | scale-qa2
1010
1111
Environment variables expected:
12-
DEV_BASE_URL, TEST_BASE_URL, QA_BASE_URL (from your Azure DevOps variable group)
12+
DEV_BASE_URL, TEST_BASE_URL, QA_BASE_URL, QA2_BASE_URL (from your Azure DevOps variable group)
1313
1414
Purpose:
1515
- Determines the correct BASE_URL from the environment.
@@ -22,7 +22,11 @@
2222
import json
2323
import urllib.request
2424

25-
REPO_COMMIT_ROOT = 'https://github.com/lantanagroup/link-cloud/commit/'
25+
REPO_COMMITS_API_ROOT = 'https://api.github.com/repos/lantanagroup/link-cloud/commits/'
26+
27+
# urlopen blocks indefinitely by default, which would hang the pipeline job rather than
28+
# fail it. Bound every HTTP call to the same budget.
29+
HTTP_TIMEOUT_SECONDS = 30
2630

2731
def fail(msg: str):
2832
print(f"ERROR: {msg}", file=sys.stderr)
@@ -43,6 +47,7 @@ def main():
4347
dev_url = os.getenv("DEV_BASE_URL", "")
4448
test_url = os.getenv("TEST_BASE_URL", "")
4549
qa_url = os.getenv("QA_BASE_URL", "")
50+
qa2_url = os.getenv("QA2_BASE_URL", "")
4651

4752
base_url = ""
4853
if input_value.startswith("https://"):
@@ -56,12 +61,14 @@ def main():
5661
base_url = test_url
5762
elif environment == "scale-qa":
5863
base_url = qa_url
64+
elif environment == "scale-qa2":
65+
base_url = qa2_url
5966
else:
60-
fail(f"Unknown environment '{environment}'. Expected one of: dev-scale | scale-test | scale-qa, or a direct https:// URL")
67+
fail(f"Unknown environment '{environment}'. Expected one of: dev-scale | scale-test | scale-qa | scale-qa2, or a direct https:// URL")
6168

6269
if not base_url:
6370
fail(f"BASE_URL is empty for environment '{environment}'. "
64-
f"Ensure DEV_BASE_URL / TEST_BASE_URL / QA_BASE_URL are defined.")
71+
f"Ensure DEV_BASE_URL / TEST_BASE_URL / QA_BASE_URL / QA2_BASE_URL are defined.")
6572

6673
print(f"Environment: {environment}")
6774
print(f"BASE_URL: {base_url}")
@@ -75,7 +82,7 @@ def main():
7582
info_url,
7683
headers={'Accept': 'application/json'}
7784
)
78-
with urllib.request.urlopen(request) as response:
85+
with urllib.request.urlopen(request, timeout=HTTP_TIMEOUT_SECONDS) as response:
7986
body = response.read().decode("utf-8")
8087
except Exception as e:
8188
fail(f"Failed to GET {info_url}: {e}")
@@ -96,20 +103,34 @@ def main():
96103
if not commit:
97104
fail("Could not find 'Commit' in /api/info response.")
98105

99-
# If we got a short hash, try to match it with the full hash from git log
106+
# If we got a short hash, resolve it to the full hash. list-deploy-changes.py fetches both
107+
# refs with 'git fetch origin <ref>', and GitHub only serves unadvertised objects by full SHA.
108+
# The 'sha' media type returns the 40-character hash as plain text.
100109
if len(commit) < 40: # Full SHA-1 hash is 40 characters
101110
print(f"Attempting to translate short commit hash {commit} to full commit hash")
102111
try:
103112
request = urllib.request.Request(
104-
f"{REPO_COMMIT_ROOT}{commit}",
105-
headers={'Accept': 'application/json'}
113+
f"{REPO_COMMITS_API_ROOT}{commit}",
114+
headers={'Accept': 'application/vnd.github.sha'}
106115
)
107-
with urllib.request.urlopen(request) as response:
108-
full_commit_data = json.loads(response.read().decode("utf-8"))
109-
commit = full_commit_data.get('payload', {}).get('commit', {}).get("sha2", commit)
116+
with urllib.request.urlopen(request, timeout=HTTP_TIMEOUT_SECONDS) as response:
117+
full_commit = response.read().decode("utf-8").strip()
118+
119+
if len(full_commit) == 40:
120+
commit = full_commit
121+
else:
122+
print(f"Warning: Unexpected response resolving full commit hash: '{full_commit[:100]}'", file=sys.stderr)
110123
except Exception as e:
111124
print(f"Warning: Could not resolve full commit hash: {e}", file=sys.stderr)
112125

126+
# A short hash breaks the downstream fetch in list-deploy-changes.py: 'git fetch origin
127+
# <ref>' is rejected for anything but a full SHA, and that failure is swallowed, so the
128+
# summary comes out empty with nothing in the log to explain it. Stop here instead of
129+
# publishing a FromCommit that cannot be used.
130+
if len(commit) < 40:
131+
fail(f"'{commit}' is not a full commit hash and could not be resolved to one. "
132+
f"'git fetch origin {commit}' would fail and the deployment summary would be empty.")
133+
113134
print(f"FromCommit: {commit}")
114135

115136
# 5. Emit Azure DevOps logging command

0 commit comments

Comments
 (0)