-
Notifications
You must be signed in to change notification settings - Fork 163
Automation to bump rocm-libraries submodule daily #2401
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
base: main
Are you sure you want to change the base?
Changes from all commits
1a822dc
8e2661a
a5e3cee
9bdb816
25ecb89
a574083
684853c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| name: Bump rocm-libraries submodule | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| schedule: | ||
| # 2:00 AM PST → 10:00 UTC, Monday–Friday | ||
| - cron: "0 10 * * 1-5" | ||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| jobs: | ||
| bump-submodules: | ||
| runs-on: ubuntu-24.04 | ||
| steps: | ||
| - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | ||
| - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 | ||
| with: | ||
| python-version: '3.12' | ||
| - name: Configure Git Identity | ||
| run: | | ||
| git config --global user.name "therockbot" | ||
| git config --global user.email "[email protected]" | ||
|
|
||
| - name: Set branch name | ||
| id: set-branch | ||
| run: | | ||
| DATE=$(date +%Y%m%d) | ||
| BRANCH="github-action/bump-rocm-libraries-submodule-$DATE" | ||
| echo "branch-name=$BRANCH" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: Generate GitHub App token | ||
| uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94 # v2.2.0 | ||
| id: generate-token | ||
| with: | ||
| app-id: ${{ secrets.PULL_REQUEST_APP_ID }} | ||
| private-key: ${{ secrets.PULL_REQUEST_APP_KEY }} | ||
|
|
||
| - name: Run bump_submodules.py | ||
| env: | ||
| GH_TOKEN: ${{ steps.generate-token.outputs.token }} | ||
| run: | | ||
| python3 ./build_tools/bump_submodules.py --push-branch \ | ||
| --branch-name ${{ steps.set-branch.outputs.branch-name }} \ | ||
| --components rocm-libraries" | ||
|
Comment on lines
+41
to
+44
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trailing
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was waiting on the final go ahead to fix all the pre-commit issues.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The final go will be the approval but we cannot approve before this wasn't addressed thus not sure what you're looking for.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a syntax error here. Did you test the workflow (on your fork)? pre-commit is for formatting issues. You should install the pre-commit git hook or otherwise run pre-commit manually yourself. We should never see pre-commit failures on PRs if you have that properly configured. See https://github.com/ROCm/TheRock/blob/main/CONTRIBUTING.md#pre-commit-checks |
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,9 +2,9 @@ | |||||||||||||||||||||||||
| """Helper script to bump TheRock's submodules, doing the following: | ||||||||||||||||||||||||||
| * (Optional) Creates a new branch | ||||||||||||||||||||||||||
| * Updates submodules from remote using `fetch_sources.py` | ||||||||||||||||||||||||||
| * Creares a commit and tries to apply local patches | ||||||||||||||||||||||||||
| * Creates a commit and tries to apply local patches | ||||||||||||||||||||||||||
| * (Optional) Pushed the new branch to origin | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| * (Optional) Create pull request from the new branch to origin (requires gh cli installed) | ||||||||||||||||||||||||||
| The submodules to bump can be specified via `--components`. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Examples: | ||||||||||||||||||||||||||
|
|
@@ -27,6 +27,7 @@ | |||||||||||||||||||||||||
| import shlex | ||||||||||||||||||||||||||
| import subprocess | ||||||||||||||||||||||||||
| import sys | ||||||||||||||||||||||||||
| import shutil | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| THIS_SCRIPT_DIR = Path(__file__).resolve().parent | ||||||||||||||||||||||||||
| THEROCK_DIR = THIS_SCRIPT_DIR.parent | ||||||||||||||||||||||||||
|
|
@@ -36,7 +37,6 @@ def log(*args, **kwargs): | |||||||||||||||||||||||||
| print(*args, **kwargs) | ||||||||||||||||||||||||||
| sys.stdout.flush() | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def exec(args: list[str | Path], cwd: Path): | ||||||||||||||||||||||||||
| args = [str(arg) for arg in args] | ||||||||||||||||||||||||||
| log(f"++ Exec [{cwd}]$ {shlex.join(args)}") | ||||||||||||||||||||||||||
|
|
@@ -63,6 +63,69 @@ def pin_ck(): | |||||||||||||||||||||||||
| cwd=THEROCK_DIR / "ml-libs" / "composable_kernel", | ||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def get_component_submodules(component: str) -> list[str]: | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| Returns the list of submodule paths belonging to the component. | ||||||||||||||||||||||||||
| Reads .gitmodules to ensure accuracy. | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| gitmodules_path = THEROCK_DIR / ".gitmodules" | ||||||||||||||||||||||||||
| content = gitmodules_path.read_text() | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| paths = [] | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| for line in content.splitlines(): | ||||||||||||||||||||||||||
| line = line.strip() | ||||||||||||||||||||||||||
| if line.startswith("path = "): | ||||||||||||||||||||||||||
| sub_path = line.split("=", 1)[1].strip() | ||||||||||||||||||||||||||
| if sub_path == component or sub_path.startswith(component + "/"): | ||||||||||||||||||||||||||
| paths.append(sub_path) | ||||||||||||||||||||||||||
| return paths | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def get_submodule_hash(path: str) -> str: | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| Returns the commit hash for a submodule path. | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| output = subprocess.check_output( | ||||||||||||||||||||||||||
| ["git", "submodule", "status", path], | ||||||||||||||||||||||||||
| cwd=str(THEROCK_DIR), | ||||||||||||||||||||||||||
| text=True | ||||||||||||||||||||||||||
| ).strip() | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| commit = output.split()[0].lstrip("+ -") | ||||||||||||||||||||||||||
| return commit | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def get_hashes_for_component(component: str) -> dict: | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| Returns {submodule_path: hash} for the component. | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| submodules = get_component_submodules(component) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| hashes = {} | ||||||||||||||||||||||||||
| for sm in submodules: | ||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||
| h = get_submodule_hash(sm) | ||||||||||||||||||||||||||
| hashes[sm] = h | ||||||||||||||||||||||||||
| except Exception as e: | ||||||||||||||||||||||||||
| log(f"Failed to read hash for {sm}: {e}") | ||||||||||||||||||||||||||
| return hashes | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def detect_hash_change(old: dict, new: dict): | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| Return (old_hash, new_hash, path) for the first changed submodule. | ||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||
| for path in new: | ||||||||||||||||||||||||||
| old_h = old.get(path) | ||||||||||||||||||||||||||
| new_h = new[path] | ||||||||||||||||||||||||||
| if old_h != new_h: | ||||||||||||||||||||||||||
| log(f"CHANGE DETECTED in {path}: {old_h} -> {new_h}") | ||||||||||||||||||||||||||
| return old_h, new_h, path | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| log("No changes detected for component") | ||||||||||||||||||||||||||
| return None, None, None | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def parse_components(components: list[str]) -> list[list]: | ||||||||||||||||||||||||||
| arguments = [] | ||||||||||||||||||||||||||
|
|
@@ -123,13 +186,8 @@ def parse_components(components: list[str]) -> list[list]: | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def run(args: argparse.Namespace, fetch_args: list[str], system_projects: list[str]): | ||||||||||||||||||||||||||
| date = datetime.today().strftime("%Y%m%d") | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if args.create_branch or args.push_branch: | ||||||||||||||||||||||||||
| exec( | ||||||||||||||||||||||||||
| ["git", "checkout", "-b", args.branch_name], | ||||||||||||||||||||||||||
| cwd=THEROCK_DIR, | ||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||
| component = args.components[0] | ||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not confident this works. This only takes the first component but ignores if a user passes a list of components. While this is acceptable for the intended use case, it breaks the script when using it to bump more than one component as far as I see. Either this needs to be addressed properly or the changes for automation must go to it's own script. |
||||||||||||||||||||||||||
| old_hashes = get_hashes_for_component(component) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if system_projects: | ||||||||||||||||||||||||||
| projects_args = ["--system-projects"] + system_projects | ||||||||||||||||||||||||||
|
|
@@ -151,10 +209,28 @@ def run(args: argparse.Namespace, fetch_args: list[str], system_projects: list[s | |||||||||||||||||||||||||
| if args.pin_ck: | ||||||||||||||||||||||||||
| pin_ck() | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| exec( | ||||||||||||||||||||||||||
| ["git", "commit", "-a", "-m", "Bump submodules " + date], | ||||||||||||||||||||||||||
| cwd=THEROCK_DIR, | ||||||||||||||||||||||||||
| # Detect new hashes BEFORE commit/branch creation | ||||||||||||||||||||||||||
| new_hashes = get_hashes_for_component(component) | ||||||||||||||||||||||||||
| old_h, new_h, changed_path = detect_hash_change(old_hashes, new_hashes) | ||||||||||||||||||||||||||
| if not old_h or not new_h: | ||||||||||||||||||||||||||
| log("No submodule changes detected – aborting without commit, branch, or PR.") | ||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if args.create_branch or args.push_branch or args.create_pr: | ||||||||||||||||||||||||||
| exec(["git", "checkout", "-b", args.branch_name], cwd=THEROCK_DIR) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Prepare commit/PR title/body | ||||||||||||||||||||||||||
| pr_title = f"Bump {component} from {old_h[:7]} to {new_h[:7]}" | ||||||||||||||||||||||||||
| pr_body = ( | ||||||||||||||||||||||||||
| f"Bump happened on {datetime.today().strftime('%m%d%Y')}\n\n" | ||||||||||||||||||||||||||
| "### Submodule changes:\n" | ||||||||||||||||||||||||||
| + "".join( | ||||||||||||||||||||||||||
| f"- `{sm}`: {old_hashes.get(sm)} → {new_hashes.get(sm)}\n" | ||||||||||||||||||||||||||
| for sm in new_hashes | ||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||
| commit_msg = pr_title + "\n\n" + pr_body | ||||||||||||||||||||||||||
| exec(["git", "commit", "-a", "-m", commit_msg], cwd=THEROCK_DIR) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||
| exec( | ||||||||||||||||||||||||||
|
|
@@ -169,8 +245,21 @@ def run(args: argparse.Namespace, fetch_args: list[str], system_projects: list[s | |||||||||||||||||||||||||
| exec( | ||||||||||||||||||||||||||
| ["git", "push", "-u", "origin", args.branch_name], | ||||||||||||||||||||||||||
| cwd=THEROCK_DIR, | ||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||
| # Create PR | ||||||||||||||||||||||||||
| if args.create_pr: | ||||||||||||||||||||||||||
| if not shutil.which("gh"): | ||||||||||||||||||||||||||
| raise SystemExit("ERROR: --create-pr requires the `gh` CLI.\n") | ||||||||||||||||||||||||||
|
Comment on lines
+251
to
+252
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Eventually check earlier and before creating the commit and pushing the branch?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes move that to argument parsing, like here: TheRock/build_tools/github_actions/post_build_upload.py Lines 346 to 357 in 83ec4f0
We can add an example like that to the style guide if it would help: https://github.com/ROCm/TheRock/blob/main/docs/development/style_guide.md#use-argparse-for-cli-flags |
||||||||||||||||||||||||||
| exec( | ||||||||||||||||||||||||||
| [ | ||||||||||||||||||||||||||
| "gh", "pr", "create", | ||||||||||||||||||||||||||
| "--title", pr_title, | ||||||||||||||||||||||||||
| "--body", pr_body, | ||||||||||||||||||||||||||
| "--head", args.branch_name, | ||||||||||||||||||||||||||
| "--base", "main", | ||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||
| cwd=THEROCK_DIR, | ||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| def main(argv): | ||||||||||||||||||||||||||
| parser = argparse.ArgumentParser(prog="bump_submodules") | ||||||||||||||||||||||||||
|
|
@@ -214,10 +303,16 @@ def main(argv): | |||||||||||||||||||||||||
| profiler | ||||||||||||||||||||||||||
| """, | ||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||
| parser.add_argument( | ||||||||||||||||||||||||||
| "--create-pr", | ||||||||||||||||||||||||||
| default=False, | ||||||||||||||||||||||||||
| action=argparse.BooleanOptionalAction, | ||||||||||||||||||||||||||
| help="Create a GitHub PR (requires `gh` CLI)", | ||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||
| args = parser.parse_args(argv) | ||||||||||||||||||||||||||
| fetch_args, system_projects = parse_components(args.components) | ||||||||||||||||||||||||||
| run(args, fetch_args, system_projects) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if __name__ == "__main__": | ||||||||||||||||||||||||||
| main(sys.argv[1:]) | ||||||||||||||||||||||||||
| main(sys.argv[1:]) | ||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing newline. |
||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.