Skip to content

Commit

Permalink
Save CI test reports to S3.
Browse files Browse the repository at this point in the history
  • Loading branch information
benjyw committed Jun 7, 2023
1 parent 2103025 commit 0444503
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 27 deletions.
57 changes: 33 additions & 24 deletions build-support/bin/copy_to_s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,17 @@ def main() -> None:
help="The AWS region to connect to.",
default="us-east-1",
)
parser.add_argument(
"--acl",
help="An optional ACL to set on copied objects.",
)
options = parser.parse_args()
perform_copy(
src_prefix=options.src_prefix,
dst_prefix=options.dst_prefix,
path=options.path,
dst_region=options.dst_region,
region=options.region,
acl=options.acl,
)


Expand All @@ -65,7 +70,8 @@ def perform_copy(
src_prefix: str,
dst_prefix: str,
path: str,
dst_region: str,
region: str,
acl: str | None = None,
aws_cli_symlink_path: str | None = None,
) -> None:
"""Recursively copy the files at src_prefix/src_path to S3.
Expand All @@ -75,14 +81,15 @@ def perform_copy(
:param path: The relpath under the src_prefix to copy.
src_prefix/path will be (recursively) copied to dst_prefix/path.
If empty, the entire src_prefix will be copied.
:param dst_region: The AWS region to access (should be the one the bucket is in).
:param region: The AWS region to access (should be the one the bucket is in).
:param acl: An optional ACL to set on the copied objects.
:param aws_cli_symlink_path: If specified, symlink the aws cli into this dir. Otherwise,
it will be synlinked into the system standard Path.
"""
if shutil.which("aws") is None:
_install_aws_cli(symlink_path=aws_cli_symlink_path)
_validate_authentication()
_copy(src_prefix=src_prefix, dst_prefix=dst_prefix, path=path, dst_region=dst_region)
_copy(src_prefix=src_prefix, dst_prefix=dst_prefix, path=path, region=region, acl=acl)


def _install_aws_cli(symlink_path: str | None = None) -> None:
Expand All @@ -105,7 +112,7 @@ def _validate_relpath(path_str: str, descr: str) -> None:
raise ValueError(f"{descr} `{path_str}` must be a relative path with no parent refs")


def _copy(src_prefix: str, dst_prefix: str, path: str, dst_region: str) -> None:
def _copy(src_prefix: str, dst_prefix: str, path: str, region: str, acl: str | None = None) -> None:
_validate_relpath(src_prefix, "src_prefix")
_validate_relpath(path, "path")
if not dst_prefix.startswith("s3://"):
Expand All @@ -116,27 +123,29 @@ def _copy(src_prefix: str, dst_prefix: str, path: str, dst_region: str) -> None:
copy_from = os.path.join(src_prefix, path)
copy_to = f"{dst_prefix}/{path}"

if not os.path.exists(copy_from):
logger.warning(f"Local path {copy_from} does not exist. Skipping copy to s3.")
return

# NB: we use the sync command to avoid transferring files that have not changed. See
# https://github.com/pantsbuild/pants/issues/7258.
_run(
[
"aws",
"--region",
dst_region,
"s3",
"sync",
# This instructs the sync command to ignore timestamps, which we must do to allow
# distinct shards—which may finish building their wheels at different times—to not
# overwrite otherwise-identical wheels.
"--size-only",
# Turn off the dynamic progress display, which clutters the CI output.
"--no-progress",
"--acl",
"public-read",
copy_from,
copy_to,
]
)
cmd = [
"aws",
"--region",
region,
"s3",
"sync",
# This instructs the sync command to ignore timestamps, which we must do to allow
# distinct shards—which may finish building their wheels at different times—to not
# overwrite otherwise-identical wheels.
"--size-only",
# Turn off the dynamic progress display, which clutters the CI output.
"--no-progress",
*(["--acl", acl] if acl else []),
copy_from,
copy_to,
]
_run(cmd)


if __name__ == "__main__":
Expand Down
3 changes: 2 additions & 1 deletion build-support/bin/deploy_to_s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ def perform_deploy(*, aws_cli_symlink_path: str | None = None, scope: str | None
src_prefix="dist/deploy",
dst_prefix="s3://binaries.pantsbuild.org",
path=scope or "",
dst_region="us-east-1",
region="us-east-1",
acl="public-read",
aws_cli_symlink_path=aws_cli_symlink_path,
)

Expand Down
36 changes: 34 additions & 2 deletions build-support/bin/generate_github_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import argparse
import os
from dataclasses import dataclass
from datetime import datetime, timezone
from enum import Enum
from pathlib import Path
from textwrap import dedent
Expand Down Expand Up @@ -545,8 +546,38 @@ def upload_log_artifacts(self, name: str) -> Step:
"if": "always()",
"continue-on-error": True,
"with": {
"name": f"pants-log-{name.replace('/', '_')}-{self.platform_name()}",
"path": ".pants.d/pants.log",
"name": f"logs-{name.replace('/', '_')}-{self.platform_name()}",
"path": ".pants.d/*.log",
},
}

def upload_test_reports(self) -> Step:
date_str = datetime.now(timezone.utc).date().isoformat()
# The path doesn't include job ID, as we want to aggregate test reports across all
# jobs/shards in a workflow. We do, however, qualify by run attempt, so we capture
# separate reports for tests that flake between attempts on the same workflow run.
s3_path = (
"test/reports/"
+ self.platform_name()
+ "/"
+ date_str
+ "/${GITHUB_REF}/${GITHUB_RUN_ID}/${GITHUB_RUN_ATTEMPT}"
)
return {
"name": "Upload test reports",
"if": "always()",
"continue-on-error": True,
"run": dedent(
f"""\
./build-support/bin/copy_to_s3.py \
--src-prefix=dist/test/reports \
--dst-prefix=s3://logs.pantsbuild.org/{s3_path} \
--path=
"""
),
"env": {
"AWS_SECRET_ACCESS_KEY": f"{gha_expr('secrets.AWS_SECRET_ACCESS_KEY')}",
"AWS_ACCESS_KEY_ID": f"{gha_expr('secrets.AWS_ACCESS_KEY_ID')}",
},
}

Expand Down Expand Up @@ -685,6 +716,7 @@ def test_jobs(
"name": human_readable_step_name,
"run": pants_args_str,
},
helper.upload_test_reports(),
helper.upload_log_artifacts(name=log_name),
],
}
Expand Down
3 changes: 3 additions & 0 deletions pants.ci.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
[GLOBAL]
colors = true

[test]
report = true

[pytest]
args = ["--no-header", "--noskip", "-vv"]

Expand Down

0 comments on commit 0444503

Please sign in to comment.