Skip to content

Add release branch automation script for TheRock and ROCm submodules#52

Merged
amd-chiranjeevi merged 5 commits into
mainfrom
users/amd-chiranjeevi/rel_branching_script
Jun 24, 2026
Merged

Add release branch automation script for TheRock and ROCm submodules#52
amd-chiranjeevi merged 5 commits into
mainfrom
users/amd-chiranjeevi/rel_branching_script

Conversation

@amd-chiranjeevi

Copy link
Copy Markdown
Contributor

Motivation

TheRock's release process requires creating release branches across TheRock and all its tracked ROCm submodules at a specific commit. Doing this manually is error-prone and time-consuming given the number of submodules involved. This script automates the entire workflow end-to-end.

Technical Details

  1. Implemented as RockBranchingAutomation class with two phases: plan building and plan execution.
  2. build_plan() clones/caches TheRock, hard-resets to the target commit, populates submodules via fetch_sources.py (fallback: git submodule update), and parses .gitmodules + git submodule status to build a per-repo execution plan. Non-ROCm repos and --exclude-list entries are filtered out.
  3. execute_plan() iterates each repo: sets up an authenticated rocm-github remote, checks for pre-existing branches via git ls-remote, creates the branch with git checkout -B, and pushes (unless dry-run).
  4. Dry-run enabled by default; --no-dry-run enables actual pushes.

Test Plan

  1. Syntax validation: python3 -c "import py_compile; py_compile.compile('create_release_branch.py', doraise=True)"
  2. Dry-run execution against a known TheRock commit to verify plan generation, submodule resolution, remote branch existence checks, and exclude-list filtering without pushing.
  3. End-to-end test with --no-dry-run on a test fork to confirm branches are created and pushed correctly across all submodules.
  4. Verify --force-clone correctly handles corrupted cache directories and --cache-dir overrides the default path.

Test Result

  1. Script compiles without errors.
  2. Dry-run produces correct execution plan with expected submodule commits, URLs, and paths.
  3. Excluded repos and non-ROCm repos are filtered from the plan.
  4. Pre-existing remote branches are detected and the repo is skipped with a logged failure.
  5. Cached clone reuse works across repeated runs via fetch/prune without recloning.
  6. --force-clone deletes and reclones when the cache is not a valid git repo

@amd-chiranjeevi

Copy link
Copy Markdown
Contributor Author

moved code from #36 to this new PR. Since author of that is not available in this project.

Hi @araravik-psd, your last comment was addressed in the PR #36 , please review and let me know if any new changes are required.

@araravik-psd araravik-psd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HI @amd-chiranjeevi a few more comments that might be needed, please take a look

Comment thread scripts/create_release_branch.py
Comment thread scripts/create_release_branch.py
Comment thread scripts/create_release_branch.py

@araravik-psd araravik-psd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @amd-chiranjeevi, changes look good, please take a look at the below exception handling cases. Do we have a test run for these changes?

continue

try:
branch_exists = self._remote_branch_exists(info.path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

execute_plan only catches CalledProcessError, not subprocess.TimeoutExpired. A network timeout on ls-remote or push will crash the entire run instead of failing just that repo. Add TimeoutExpired to every except block in execute_plan

Add a except that catches both exceptions in the two blocks that do network I/O:

try:
    branch_exists = self._remote_branch_exists(info.path)
except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as exc:
    failed_repos[repo_name] = (
        f"Remote branch check failed: {exc}"
    )
    continue

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

continue

try:
self._push_branch(repo_name, info.path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar changes as above here to handle exception

try:
    self._push_branch(repo_name, info.path)
    successful_repos[repo_name] = info
except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as exc:
    failed_repos[repo_name] = f"Branch push failed: {exc}"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks changes done.

Comment thread scripts/create_release_branch.py Outdated
level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s"
)

RockBranchingAutomation(args).run()

@araravik-psd araravik-psd Jun 24, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main() swallows exceptions here, errors produce a raw traceback instead of a clean exit
RockBranchingAutomation(args).run() can raise RuntimeError (from cache validation in def build_plan()), subprocess.CalledProcessError, or subprocess.TimeoutExpired. Any of these crash with a raw Python traceback rather than a clean message. Wrap it with a try except loop:

try:
    RockBranchingAutomation(args).run()
    return 0
except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as exc:
    logging.error("Command failed: %s", exc)
    return 1
except RuntimeError as exc:
    logging.error("%s", exc)
    return 1
except Exception as exc:
    logging.error("Unexpected error: %s", exc)
    return 1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. changes done.

@amd-chiranjeevi

amd-chiranjeevi commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

Hi @amd-chiranjeevi, changes look good, please take a look at the below exception handling cases. Do we have a test run for these changes?

yes Aravind, I have tested and created in repos

 uv run create_release_branch.py --branch-name users/amd-chiranjeevi/test_branch_2 --commitid cdc7cfea960aaf2035613eb99a7baa246d3419cf --cache-dir /home/cpattigi/release-branching-tagging/rock-repos-cache --no-dry-run

conformed by checking the repos ex: https://github.com/ROCm/rocm-cmake/commits/users/amd-chiranjeevi/test_branch_2/ , https://github.com/ROCm/half/tree/users/amd-chiranjeevi/test_branch_2
branch created with same commit as rock pointed in tree https://github.com/ROCm/TheRock/tree/cdc7cfea960aaf2035613eb99a7baa246d3419cf/base

@amd-chiranjeevi

Copy link
Copy Markdown
Contributor Author

Unit tests execution:

$$ uv run pytest tests/test_create_release_branch.py -v
==================================================================== test session starts ====================================================================
platform linux -- Python 3.14.4, pytest-9.1.1, pluggy-1.6.0 -- /home/cpattigi/test_branching_code/rockrel/scripts/.venv/bin/python3
cachedir: .pytest_cache
rootdir: /home/cpattigi/test_branching_code/rockrel/scripts
configfile: pyproject.toml
collected 25 items                                                                                                                                          

tests/test_create_release_branch.py::TestConvertToSsh::test_https_converted PASSED                                                                    [  4%]
tests/test_create_release_branch.py::TestConvertToSsh::test_https_without_dot_git PASSED                                                              [  8%]
tests/test_create_release_branch.py::TestConvertToSsh::test_ssh_url_passthrough PASSED                                                                [ 12%]
tests/test_create_release_branch.py::TestConvertToSsh::test_non_github_url_passthrough PASSED                                                         [ 16%]
tests/test_create_release_branch.py::TestRocmOrgFilter::test_rocm_org_detection[https://github.com/ROCm/hip.git-True] PASSED                          [ 20%]
tests/test_create_release_branch.py::TestRocmOrgFilter::test_rocm_org_detection[https://github.com/rocm/hip.git-True] PASSED                          [ 24%]
tests/test_create_release_branch.py::TestRocmOrgFilter::test_rocm_org_detection[git@github.com:ROCm/clr.git-True] PASSED                              [ 28%]
tests/test_create_release_branch.py::TestRocmOrgFilter::test_rocm_org_detection[git@github.com:rocm/clr.git-True] PASSED                              [ 32%]
tests/test_create_release_branch.py::TestRocmOrgFilter::test_rocm_org_detection[https://github.com/llvm/llvm-project.git-False] PASSED                [ 36%]
tests/test_create_release_branch.py::TestRocmOrgFilter::test_rocm_org_detection[https://github.com/other/repo.git-False] PASSED                       [ 40%]
tests/test_create_release_branch.py::TestRocmOrgFilter::test_rocm_org_detection[https://gitlab.com/ROCm/hip.git-False] PASSED                         [ 44%]
tests/test_create_release_branch.py::TestGetSubmoduleUrlMap::test_no_gitmodules_returns_empty PASSED                                                  [ 48%]
tests/test_create_release_branch.py::TestGetSubmoduleUrlMap::test_parses_paths_and_urls PASSED                                                        [ 52%]
tests/test_create_release_branch.py::TestGetSubmoduleUrlMap::test_missing_url_entry_skipped PASSED                                                    [ 56%]
tests/test_create_release_branch.py::TestExecutePlan::test_dry_run_does_not_push PASSED                                                               [ 60%]
tests/test_create_release_branch.py::TestExecutePlan::test_existing_remote_branch_goes_to_skipped_not_failed PASSED                                   [ 64%]
tests/test_create_release_branch.py::TestExecutePlan::test_missing_repo_path_recorded_as_failure PASSED                                               [ 68%]
tests/test_create_release_branch.py::TestExecutePlan::test_setup_remote_failure_recorded_not_raised PASSED                                            [ 72%]
tests/test_create_release_branch.py::TestExecutePlan::test_create_branch_failure_recorded_not_raised PASSED                                           [ 76%]
tests/test_create_release_branch.py::TestExecutePlan::test_successful_dry_run_calls_create_branch PASSED                                              [ 80%]
tests/test_create_release_branch.py::TestExecutePlan::test_no_dry_run_calls_push PASSED                                                               [ 84%]
tests/test_create_release_branch.py::TestCommitidValidation::test_valid_sha_accepted PASSED                                                           [ 88%]
tests/test_create_release_branch.py::TestCommitidValidation::test_short_sha_rejected PASSED                                                           [ 92%]
tests/test_create_release_branch.py::TestCommitidValidation::test_uppercase_sha_rejected PASSED                                                       [ 96%]
tests/test_create_release_branch.py::TestCommitidValidation::test_non_hex_rejected PASSED                                                             [100%]

==================================================================== 25 passed in 0.10s =====================================================================

@araravik-psd araravik-psd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amd-chiranjeevi thanks for addressing the review comments

@amd-chiranjeevi amd-chiranjeevi merged commit e8322db into main Jun 24, 2026
1 check passed
@amd-chiranjeevi amd-chiranjeevi deleted the users/amd-chiranjeevi/rel_branching_script branch June 24, 2026 20:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants