Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 66 additions & 2 deletions tests/test_the_test/test_update_agent_version.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import subprocess
import urllib.error
from pathlib import Path

from utils import pytest
Expand All @@ -13,6 +14,7 @@
enable_auto_merge,
normalize_version,
publish_update,
push_signed_commit,
revoke_token,
run_automation,
update_agent_version,
Expand Down Expand Up @@ -194,16 +196,39 @@ def fake_run(
) -> subprocess.CompletedProcess[str]:
assert env == {"GH_TOKEN": "token"}
commands.append(args)
return subprocess.CompletedProcess(args, 0, stdout="" if capture_output else None)
if not capture_output:
return subprocess.CompletedProcess(args, 0, stdout=None)
if args == ["git", "rev-parse", "HEAD"]:
return subprocess.CompletedProcess(args, 0, stdout="main-sha\n")
if args[0] == "commit-headless":
return subprocess.CompletedProcess(args, 0, stdout="signed-sha\n")
return subprocess.CompletedProcess(args, 0, stdout="")

monkeypatch.setattr("utils.scripts.update_agent_version.run_command", fake_run)

github = FakeGitHubApi()
publish_update(tmp_path, "7.82.3", github, {"GH_TOKEN": "token"})

assert ["git", "rev-parse", "HEAD"] in commands
assert ["git", "add", str(AGENT_VERSION_LOCK)] in commands
assert ["git", "push", "--force", "--set-upstream", "origin", AUTOMATION_BRANCH] in commands
# The fake GitHub API never raises a 404 for the branch-existence check, so the branch is
# always treated as already existing and force-updated.
assert [
"commit-headless",
"push",
"-T",
"DataDog/system-tests",
"--branch",
AUTOMATION_BRANCH,
"--head-sha",
"main-sha",
"--force",
] in commands
assert not any(command[0] == "gh" for command in commands)
assert any(
method == "GET" and path == f"/repos/DataDog/system-tests/git/ref/heads/{AUTOMATION_BRANCH}"
for method, path in github.calls
)
assert any(method == "POST" and path.endswith("/pulls") for method, path in github.calls) is (not existing_pr)
if existing_pr:
assert ("PATCH", f"/repos/DataDog/system-tests/pulls/{existing_pr}") in github.calls
Expand All @@ -212,6 +237,45 @@ def fake_run(
assert github.calls[-1] == ("POST", "/graphql")


@scenarios.test_the_test
def test_push_signed_commit_creates_branch_when_missing(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
commands: list[list[str]] = []

class MissingBranchGitHubApi(GitHubApi):
def __init__(self) -> None:
super().__init__("token")

def request(self, method: str, path: str, data: dict[str, object] | None = None) -> object: # noqa: ARG002
raise urllib.error.HTTPError(path, 404, "Not Found", {}, None) # type: ignore[arg-type]

def fake_run(
_root: Path,
args: list[str],
*,
capture_output: bool = False, # noqa: ARG001
env: dict[str, str] | None = None, # noqa: ARG001
) -> subprocess.CompletedProcess[str]:
commands.append(args)
return subprocess.CompletedProcess(args, 0, stdout="signed-sha\n")

monkeypatch.setattr("utils.scripts.update_agent_version.run_command", fake_run)

signed_sha = push_signed_commit(tmp_path, "main-sha", MissingBranchGitHubApi(), {"GH_TOKEN": "token"})

assert signed_sha == "signed-sha"
assert [
"commit-headless",
"push",
"-T",
"DataDog/system-tests",
"--branch",
AUTOMATION_BRANCH,
"--head-sha",
"main-sha",
"--create-branch",
] in commands


def fake_github(result: object) -> GitHubApi:
class FakeGitHubApi(GitHubApi):
def request(self, method: str, path: str, data: dict[str, object] | None = None) -> object: # noqa: ARG002
Expand Down
4 changes: 4 additions & 0 deletions utils/ci/gitlab/docker/system-tests.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,8 @@ COPY --from=registry.ddbuild.io/ddsign:v1.11.10@sha256:55784668a612ab22129bb15a6
# For more information see https://datadoghq.atlassian.net/wiki/spaces/SECENG/pages/5138645099/User+guide+dd-octo-sts#%3Agitlab%3A-Via-Gitlab-CI-job
COPY --from=registry.ddbuild.io/dd-octo-sts:v1.9.3@sha256:f8412df42db2e1879182c820ea4ef600ab4375c5b696a24151c7f0dd931ffee6 /usr/local/bin/dd-octo-sts /usr/local/bin/dd-octo-sts

# Used to push signed commits to automation branches (e.g. the pinned Agent version update)
# https://github.com/DataDog/commit-headless
COPY --from=registry.ddbuild.io/commit-headless:v3.4.0@sha256:7a7c7853250c0dcd4682548a256d4e470fc4443a9a37e0c69aa83e85e53a1dbc /commit-headless /usr/local/bin/commit-headless

WORKDIR /
2 changes: 1 addition & 1 deletion utils/ci/gitlab/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ variables:
# Tag = first 12 chars of sha256(utils/ci/gitlab/docker/system-tests.Dockerfile + requirements.txt)
# Update this when either file changes:
# cat utils/ci/gitlab/docker/system-tests.Dockerfile requirements.txt | sha256sum | cut -c1-12
CI_IMAGE: "registry.ddbuild.io/system-tests/ci-runner:65e2f06534fd"
CI_IMAGE: "registry.ddbuild.io/system-tests/ci-runner:970b845364b9"
SYSTEM_TESTS_SPLIT_PIPELINE: "$[[ inputs.split_pipeline ]]"

.system_tests_param_base:
Expand Down
44 changes: 40 additions & 4 deletions utils/scripts/update_agent_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import os
import re
import subprocess
import urllib.error
import urllib.parse
import urllib.request
from pathlib import Path
Expand Down Expand Up @@ -115,19 +116,54 @@ def enable_auto_merge(github: GitHubApi, pull_request_node_id: str) -> None:
raise RuntimeError("GitHub failed to enable pull request auto-merge")


def remote_branch_exists(github: GitHubApi) -> bool:
try:
github.request("GET", f"/repos/{REPOSITORY}/git/ref/heads/{AUTOMATION_BRANCH}")
except urllib.error.HTTPError as error:
not_found = 404
if error.code == not_found:
return False
raise
return True


def push_signed_commit(root: Path, base_sha: str, github: GitHubApi, env: Mapping[str, str]) -> str:
# The branch is (re)created from main on every run, so its remote counterpart, if any, always
# needs a force-update: only its very first push can fast-forward via --create-branch.
flag = "--force" if remote_branch_exists(github) else "--create-branch"
result = run_command(
root,
[
"commit-headless",
"push",
"-T",
REPOSITORY,
"--branch",
AUTOMATION_BRANCH,
"--head-sha",
base_sha,
flag,
],
capture_output=True,
env=env,
Comment thread
nccatoni marked this conversation as resolved.
)
Comment thread
nccatoni marked this conversation as resolved.
return result.stdout.strip()


def publish_update(root: Path, version: str, github: GitHubApi, env: Mapping[str, str]) -> None:
run_command(root, ["git", "remote", "set-url", "origin", f"https://github.com/{REPOSITORY}.git"], env=env)
base_sha = run_command(root, ["git", "rev-parse", "HEAD"], capture_output=True, env=env).stdout.strip()
run_command(root, ["git", "switch", "--force-create", AUTOMATION_BRANCH], env=env)
run_command(root, ["git", "add", str(AGENT_VERSION_LOCK)], env=env)
run_command(root, ["git", "config", "user.name", "github-actions[bot]"], env=env)
run_command(root, ["git", "config", "user.email", "github-actions[bot]@users.noreply.github.com"], env=env)
run_command(
root,
["git", "config", "credential.helper", "!f() { echo username=x-access-token; echo password=$GH_TOKEN; }; f"],
["git", "config", "user.email", "github-actions[bot]@users.noreply.github.com"],
env=env,
)
run_command(root, ["git", "commit", "-m", f"Update Agent to {version}"], env=env)
run_command(root, ["git", "push", "--force", "--set-upstream", "origin", AUTOMATION_BRANCH], env=env)

signed_sha = push_signed_commit(root, base_sha, github, env)
print(f"Pushed signed commit {signed_sha} to {AUTOMATION_BRANCH}")

head = urllib.parse.quote(f"DataDog:{AUTOMATION_BRANCH}", safe="")
pull_requests = github.request("GET", f"/repos/{REPOSITORY}/pulls?head={head}&state=open")
Expand Down
Loading