Skip to content

Commit

Permalink
Add asset management script (Azure#27676)
Browse files Browse the repository at this point in the history
Co-authored-by: scbedd <[email protected]>
  • Loading branch information
mccoyp and scbedd authored Dec 6, 2022
1 parent a5ba93c commit 82c2a2a
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 5 deletions.
17 changes: 12 additions & 5 deletions doc/dev/tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -394,20 +394,26 @@ sdk/{service}/{package}/assets.json;2Km2Z8755;python/{service}/{package}_<10-cha
```
The recording directory in this case is `2Km2Z8755`, the string between the two semicolons.

After verifying that your recording updates look correct, you can use the `manage_recordings.py` script from
`azure-sdk-for-python/scripts` to push these recordings to the `azure-sdk-assets` repo. For example, from the root of
the `azure-sdk-for-python` repo:
After verifying that your recording updates look correct, you can use the [`manage_recordings.py`][manage_recordings]
script from `azure-sdk-for-python/scripts` to push these recordings to the `azure-sdk-assets` repo. This script accepts
a verb and a **relative** path to your package's `assets.json` file. For example, from the root of the
`azure-sdk-for-python` repo:
```
python scripts/manage_recordings.py push sdk/{service}/{package}/assets.json
```

**NOTE:** The `manage_recordings.py` script is still under development at the time of writing. To push updated
recordings in the meantime, refer to https://github.com/Azure/azure-sdk-tools/blob/main/tools/test-proxy/documentation/asset-sync/README.md#pushing-new-recordings.
The verbs that can be provided to this script are "push", "restore", and "reset":
- **push**: pushes recording updates to a new assets repo tag and updates the tag pointer in `assets.json`.
- **restore**: fetches recordings from the assets repo, based on the tag pointer in `assets.json`.
- **reset**: discards any pending changes to recordings, based on the tag pointer in `assets.json`.

After pushing your recordings, the `assets.json` file for your package will be updated to point to a new `Tag` that
contains the updates. Include this `assets.json` update in any pull request to update the recordings pointer in the
upstream repo.

More details about the recording management commands and management script are documented in
[`manage_recordings.py`][manage_recordings].

### Sanitize secrets

The `.json` files created from running tests in live mode can include authorization details, account names, shared
Expand Down Expand Up @@ -708,6 +714,7 @@ Tests that use the Shared Access Signature (SAS) to authenticate a client should
[kv_test_resources_outputs]: https://github.com/Azure/azure-sdk-for-python/blob/fbdb860630bcc13c1e355828231161849a9bd5a4/sdk/keyvault/test-resources.json#L255
[kv_test_resources_resources]: https://github.com/Azure/azure-sdk-for-python/blob/fbdb860630bcc13c1e355828231161849a9bd5a4/sdk/keyvault/test-resources.json#L116

[manage_recordings]: https://github.com/Azure/azure-sdk-for-python/blob/main/scripts/manage_recordings.py
[mgmt_settings_fake]: https://github.com/Azure/azure-sdk-for-python/blob/main/tools/azure-sdk-tools/devtools_testutils/mgmt_settings_fake.py

[packaging]: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/packaging.md
Expand Down
149 changes: 149 additions & 0 deletions scripts/manage_recordings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------

import argparse
import os
import shlex
import sys

try:
from dotenv import load_dotenv

load_dotenv()
except:
pass

import subprocess


# This file contains a script for managing test recordings in the azure-sdk-assets repository with Docker.
#
# INSTRUCTIONS FOR USE:
#
# - Set GIT_TOKEN, GIT_COMMIT_OWNER, and GIT_COMMIT_EMAIL environment variables to authenticate git requests.
# These can be set in-process or added to a .env file at the root of or directory above your local copy of the
# azure-sdk-for-python repository.
# - Set your working directory to be inside your local copy of the azure-sdk-for-python repository.
# - Run the following command:
#
# `python {path to script}/manage_recordings.py {verb} {relative path to package's assets.json file}`
#
# For example, with the root of the azure-sdk-for-python repo as the working directory, you can push modified
# azure-keyvault-keys recordings to the assets repo with:
#
# `python scripts/manage_recordings.py push sdk/keyvault/azure-keyvault-keys/assets.json`
#
# - In addition to "push", you can also use the "restore" or "reset" verbs in the same command format.
#
# * push: pushes recording updates to a new assets repo tag and updates the tag pointer in `assets.json`.
# * restore: fetches recordings from the assets repo, based on the tag pointer in `assets.json`.
# * reset: discards any pending changes to recordings, based on the tag pointer in `assets.json`.
#
# For more information about how recording asset synchronization, please refer to
# https://github.com/Azure/azure-sdk-tools/blob/main/tools/test-proxy/documentation/asset-sync/README.md.

# Load environment variables from user's .env file

CONTAINER_NAME = "azsdkengsys.azurecr.io/engsys/test-proxy"
GIT_TOKEN = os.getenv("GIT_TOKEN", "")
GIT_OWNER = os.getenv("GIT_COMMIT_OWNER", "")
GIT_EMAIL = os.getenv("GIT_COMMIT_EMAIL", "")


# ----- HELPERS ----- #


discovered_roots = []


def ascend_to_root(start_dir_or_file: str) -> str:
"""
Given a path, ascend until encountering a folder with a `.git` folder present within it. Return that directory.
:param str start_dir_or_file: The starting directory or file. Either is acceptable.
"""
if os.path.isfile(start_dir_or_file):
current_dir = os.path.dirname(start_dir_or_file)
else:
current_dir = start_dir_or_file

while current_dir is not None and not (os.path.dirname(current_dir) == current_dir):
possible_root = os.path.join(current_dir, ".git")

# we need the git check to prevent ascending out of the repo
if os.path.exists(possible_root):
if current_dir not in discovered_roots:
discovered_roots.append(current_dir)
return current_dir
else:
current_dir = os.path.dirname(current_dir)

raise Exception(f'Requested target "{start_dir_or_file}" does not exist within a git repo.')


def delete_container() -> None:
"""Delete container if it remained"""
proc = subprocess.Popen(
shlex.split(f"docker rm -f {CONTAINER_NAME}"),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.DEVNULL,
)
output, stderr = proc.communicate(timeout=10)
return None


def get_image_tag(repo_root: str) -> str:
"""Gets the test proxy Docker image tag from the target_version.txt file in /eng/common/testproxy"""
version_file_location = os.path.relpath("eng/common/testproxy/target_version.txt")
version_file_location_from_root = os.path.abspath(os.path.join(repo_root, version_file_location))

with open(version_file_location_from_root, "r") as f:
image_tag = f.read().strip()

return image_tag


# ----- CORE LOGIC ----- #


if not (GIT_TOKEN and GIT_OWNER and GIT_EMAIL):
raise ValueError(
"GIT_TOKEN, GIT_COMMIT_OWNER, and GIT_COMMIT_EMAIL environment variables must be set, "
"either in-process or in a .env file"
)

# Prepare command arguments
parser = argparse.ArgumentParser(description="Script for managing recording assets with Docker.")
parser.add_argument("verb", help='The action verb for managing recordings: "restore", "push", or "reset".')
parser.add_argument(
"path",
default="assets.json",
help='The *relative* path to your package\'s `assets.json` file. Default is "assets.json".',
)
args = parser.parse_args()

if args.verb and args.path:

current_directory = os.getcwd()
repo_root = ascend_to_root(current_directory)
image_tag = get_image_tag(repo_root)

root_path = os.path.abspath(repo_root)
cwd_relpath = os.path.relpath(current_directory, root_path)
assets_path = os.path.join(cwd_relpath, args.path).replace("\\", "/")

delete_container() # Delete any lingering container so a new one can be created with necessary environment variables

subprocess.run(
shlex.split(
f'docker run --rm -v "{repo_root}:/srv/testproxy" '
f'-e "GIT_TOKEN={GIT_TOKEN}" -e "GIT_COMMIT_OWNER={GIT_OWNER}" -e "GIT_COMMIT_EMAIL={GIT_OWNER}" '
f"{CONTAINER_NAME}:{image_tag} test-proxy {args.verb.lower()} -a {assets_path}"
),
stdout=sys.stdout,
stderr=sys.stderr,
)

0 comments on commit 82c2a2a

Please sign in to comment.