Repository navigation
ci: add Windows MSI install test (Milestone 5, #1987) #8669
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
135 changes: 135 additions & 0 deletions
135
.github/workflows/test_native_windows_packages_install.yml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| # Copyright Advanced Micro Devices, Inc. | ||
| # SPDX-License-Identifier: MIT | ||
|
|
||
| # Installs and verifies the Windows MSI packages produced by an arbitrary build | ||
| # run. Standalone and dispatchable (fork-friendly: MSIs are downloaded from the | ||
| # public artifacts prefix, no credentials required), and callable from | ||
| # ci/release. Mirrors test_native_linux_packages_install.yml. | ||
|
|
||
| name: Test Native Windows Packages Install | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| artifact_run_id: | ||
| description: "Run id whose published Windows MSIs to install and verify" | ||
| type: string | ||
| required: true | ||
| artifact_github_repo: | ||
| description: "GitHub repository that owns artifact_run_id" | ||
| type: string | ||
| default: ROCm/TheRock | ||
| packages: | ||
| description: "Packages to test, comma-separated (e.g. 'runtime,core')." | ||
| type: string | ||
| default: runtime | ||
| rocm_version: | ||
| description: "ROCm version stamped on the MSI (e.g. '10.2.0')." | ||
| type: string | ||
| required: true | ||
| release_type: | ||
| description: "Release type selecting the source artifacts bucket." | ||
| type: choice | ||
| options: | ||
| - ci | ||
| - dev | ||
| default: ci | ||
| run_uninstall: | ||
| description: "Also uninstall and verify a clean teardown." | ||
| type: boolean | ||
| default: true | ||
| repository: | ||
| description: "Repository to checkout. Defaults to github.repository." | ||
| type: string | ||
| default: "" | ||
| ref: | ||
| description: "Branch, tag, or SHA to checkout. Defaults to the triggering ref." | ||
| type: string | ||
| default: "" | ||
| workflow_call: | ||
| inputs: | ||
| artifact_run_id: | ||
| type: string | ||
| required: true | ||
| artifact_github_repo: | ||
| type: string | ||
| default: ROCm/TheRock | ||
| packages: | ||
| type: string | ||
| default: runtime | ||
| rocm_version: | ||
| type: string | ||
| required: true | ||
| release_type: | ||
| # Matches the MSI build workflow's default so the test reads from the | ||
| # same bucket the producer wrote to. | ||
| type: string | ||
| default: ci | ||
| run_uninstall: | ||
| type: boolean | ||
| default: true | ||
| repository: | ||
| type: string | ||
| default: "" | ||
| ref: | ||
| type: string | ||
| default: "" | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| run-name: Test Windows MSI install (${{ inputs.packages }}, ${{ inputs.rocm_version }}) | ||
|
|
||
| jobs: | ||
| test: | ||
| name: Test MSI install | ||
| runs-on: windows-2022 | ||
| defaults: | ||
| run: | ||
| shell: bash | ||
| env: | ||
| ARTIFACT_RUN_ID: ${{ inputs.artifact_run_id }} | ||
| ARTIFACT_GITHUB_REPO: ${{ inputs.artifact_github_repo }} | ||
| RELEASE_TYPE: ${{ inputs.release_type }} | ||
| PACKAGES: ${{ inputs.packages }} | ||
| ROCM_VERSION: ${{ inputs.rocm_version }} | ||
| # Download target; the install/uninstall tests consume these files via | ||
| # MSI_DIR and never touch the network themselves. | ||
| MSI_DIR: ${{ github.workspace }}/msi-packages | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| timeout-minutes: 15 | ||
| with: | ||
| persist-credentials: false | ||
| repository: ${{ inputs.repository || github.repository }} | ||
| ref: ${{ inputs.ref }} | ||
|
|
||
| - name: Set up Python | ||
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | ||
| with: | ||
| python-version: '3.12' | ||
|
|
||
| - name: Install Python requirements | ||
| run: pip install -r requirements.txt | ||
|
|
||
| # Download once; the tests below re-use these files (no network in tests). | ||
| - name: Download MSI packages | ||
| run: | | ||
| python build_tools/packaging/windows/download_msi_packages.py \ | ||
| --artifact-run-id "${ARTIFACT_RUN_ID}" \ | ||
| --artifact-github-repo "${ARTIFACT_GITHUB_REPO}" \ | ||
| --release-type "${RELEASE_TYPE}" \ | ||
| --packages "${PACKAGES}" \ | ||
| --dest-dir "${MSI_DIR}" | ||
|
|
||
| - name: Install and verify MSI packages | ||
| run: | | ||
| python -m pytest \ | ||
| build_tools/packaging/windows/native_windows_package_install_test.py -vv -s | ||
|
|
||
| - name: Uninstall and verify teardown | ||
| if: ${{ inputs.run_uninstall }} | ||
| run: | | ||
| python -m pytest \ | ||
| build_tools/packaging/windows/native_windows_package_uninstall_test.py -vv -s | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| #!/usr/bin/env python3 | ||
| # Copyright Advanced Micro Devices, Inc. | ||
| # SPDX-License-Identifier: MIT | ||
|
|
||
| """Download a build run's Windows MSI packages into a local directory. | ||
|
|
||
| Separates the download (network) step from the install/uninstall tests, which | ||
| consume the already-downloaded files via ``--msi-dir``. CI runs this once and | ||
| then runs the tests against the output directory; a developer can do the same | ||
| and re-run the tests repeatedly without re-downloading. | ||
|
|
||
| The MSIs live at the public artifacts prefix ``{run_id}-windows/packages/msi/`` | ||
| and are named ``<output_stem>.msi`` per the generator's PACKAGES table, so no S3 | ||
| listing or credentials are needed (works from forks). | ||
|
|
||
| Example:: | ||
|
|
||
| python download_msi_packages.py \\ | ||
| --artifact-run-id 36648157930 --release-type nightly \\ | ||
| --packages runtime --dest-dir ./msis | ||
| """ | ||
|
|
||
| import argparse | ||
| import sys | ||
| import urllib.error | ||
| import urllib.request | ||
| from pathlib import Path | ||
|
|
||
| sys.path.insert(0, str(Path(__file__).resolve().parent)) | ||
| from generate_msi_wxs import PACKAGES, expected_msi_filename # noqa: E402 | ||
|
|
||
| sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent)) | ||
| from _therock_utils.workflow_outputs import WorkflowOutputRoot # noqa: E402 | ||
|
|
||
| PLATFORM = "windows" | ||
| DEFAULT_ARTIFACT_GITHUB_REPO = "ROCm/TheRock" | ||
|
|
||
|
|
||
| def resolve_msi_prefix_url( | ||
| artifact_run_id: str, artifact_github_repo: str, release_type: str | ||
| ) -> str: | ||
| """Return the public HTTPS URL of the run's msi package prefix. | ||
|
|
||
| Resolves the artifacts bucket from the run id + release type without any | ||
| GitHub API call (lookup_workflow_run=False). | ||
| """ | ||
| root = WorkflowOutputRoot.from_workflow_run( | ||
| run_id=artifact_run_id, | ||
| platform=PLATFORM, | ||
| github_repository=artifact_github_repo, | ||
| release_type=release_type, | ||
| lookup_workflow_run=False, | ||
| ) | ||
| return root.native_windows_packages("msi").https_url | ||
|
|
||
|
|
||
| def download_msis(prefix_url: str, packages: list[str], dest_dir: Path) -> list[Path]: | ||
| """Download each package's MSI from the public prefix into ``dest_dir``.""" | ||
| dest_dir.mkdir(parents=True, exist_ok=True) | ||
| downloaded: list[Path] = [] | ||
| for package in packages: | ||
| filename = expected_msi_filename(package) | ||
| url = f"{prefix_url.rstrip('/')}/{filename}" | ||
| dest = dest_dir / filename | ||
| print(f"Downloading {url} -> {dest}") | ||
| try: | ||
| urllib.request.urlretrieve(url, dest) | ||
|
idass1990 marked this conversation as resolved.
Resolved
|
||
| except urllib.error.URLError as e: | ||
| raise FileNotFoundError( | ||
| f"could not download MSI for package {package!r} from {url}: {e}. " | ||
| "The build run may not have produced this package, or its MSIs " | ||
| "were not uploaded to the public prefix (fork build runs do not " | ||
| "upload)." | ||
| ) from e | ||
| downloaded.append(dest) | ||
| return downloaded | ||
|
|
||
|
|
||
| def _split_packages(value: str) -> list[str]: | ||
| return [p.strip() for p in value.split(",") if p.strip()] | ||
|
|
||
|
|
||
| def main(argv: list[str] | None = None) -> None: | ||
| parser = argparse.ArgumentParser( | ||
| description="Download a build run's Windows MSI packages to a directory." | ||
| ) | ||
| parser.add_argument( | ||
| "--artifact-run-id", | ||
| required=True, | ||
| help="Run id whose published Windows MSIs to download.", | ||
| ) | ||
| parser.add_argument( | ||
| "--artifact-github-repo", | ||
| default=DEFAULT_ARTIFACT_GITHUB_REPO, | ||
| help=f"Repository that owns the run id. Default: {DEFAULT_ARTIFACT_GITHUB_REPO}.", | ||
| ) | ||
| parser.add_argument( | ||
| "--release-type", | ||
| required=True, | ||
| help="Release type selecting the source artifacts bucket (e.g. ci, nightly).", | ||
| ) | ||
| parser.add_argument( | ||
| "--packages", | ||
| default="runtime", | ||
| help="Comma-separated packages to download (e.g. 'runtime,core').", | ||
| ) | ||
| parser.add_argument( | ||
| "--dest-dir", | ||
| type=Path, | ||
| required=True, | ||
| help="Directory to download the MSIs into.", | ||
| ) | ||
| args = parser.parse_args(argv) | ||
|
|
||
| packages = _split_packages(args.packages) | ||
| if not packages: | ||
| parser.error("--packages was empty") | ||
| unknown = [p for p in packages if p not in PACKAGES] | ||
| if unknown: | ||
| parser.error(f"unknown package(s): {', '.join(unknown)}") | ||
|
|
||
| prefix_url = resolve_msi_prefix_url( | ||
| args.artifact_run_id, args.artifact_github_repo, args.release_type | ||
| ) | ||
| paths = download_msis(prefix_url, packages, args.dest_dir) | ||
| print(f"Downloaded {len(paths)} MSI(s) to {args.dest_dir}") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.