Skip to content

Commit bff9be8

Browse files
authored
Merge pull request #69 from mxstack/feature/smart-threading-pushurl
Improve smart threading for HTTPS URLs with pushurl
2 parents a384b20 + e70b770 commit bff9be8

File tree

4 files changed

+58
-3
lines changed

4 files changed

+58
-3
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
[jensens]
1717
- Chore: Updated test fixture data versions to resolve Dependabot security alerts. Updated urllib3 from 1.26.9 to 2.5.0 and requests from 2.28.0 to 2.32.4 in test data files. These are test fixtures only and were never actual dependencies or security risks. Resolves GitHub Dependabot alerts #1-7.
1818
[jensens]
19+
- Performance: Smart threading now processes HTTPS URLs with `pushurl` in parallel. When a package defines both an HTTPS `url` and a `pushurl` (typically SSH), the HTTPS URL is assumed to be read-only/public and won't prompt for credentials, making it safe for parallel processing. This improves checkout performance for the common pattern of public repos with separate push URLs.
20+
[jensens]
1921
- Fix: Add 'synchronize' event to pull_request workflow triggers. This ensures CI runs when PRs are updated with new commits (e.g., after rebasing or pushing new changes), not just when opened or reopened.
2022
[jensens]
2123
- Chore: Optimize GitHub Actions to prevent duplicate workflow runs on pull requests. Restrict `push` trigger to only run on `main` branch, so PRs only trigger via `pull_request` event. This reduces CI resource usage by 50% for PR workflows.

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,10 @@ The **main section** must be called `[settings]`, even if kept empty.
9494

9595
When `smart-threading` is enabled (default), mxdev uses a two-phase approach to prevent credential prompts from overlapping:
9696

97-
1. **Phase 1**: HTTPS packages are processed serially (one at a time) to ensure clean, visible credential prompts
98-
2. **Phase 2**: Remaining packages (SSH, local) are processed in parallel for speed
97+
1. **Phase 1**: HTTPS packages **without `pushurl`** are processed serially (one at a time) to ensure clean, visible credential prompts
98+
2. **Phase 2**: Remaining packages (SSH, local, HTTPS with `pushurl`) are processed in parallel for speed
99+
100+
**Optimization**: HTTPS URLs with `pushurl` defined are assumed to be read-only/public and processed in parallel, since the `pushurl` indicates authenticated write access is separate.
99101

100102
This solves the problem where parallel git operations would cause multiple credential prompts to overlap, making it confusing which package needs credentials.
101103

src/mxdev/vcs/common.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ def __init__(
175175
def _separate_https_packages(self, packages: list[str]) -> tuple[list[str], list[str]]:
176176
"""Separate HTTPS packages from others for smart threading.
177177
178+
HTTPS packages WITH pushurl are safe for parallel processing
179+
(pushurl implies the https url is read-only/public).
180+
178181
Returns (https_packages, other_packages)
179182
"""
180183
https_packages = []
@@ -186,9 +189,13 @@ def _separate_https_packages(self, packages: list[str]) -> tuple[list[str], list
186189
continue
187190
source = self.sources[name]
188191
url = source.get("url", "")
189-
if url.startswith("https://"):
192+
has_pushurl = "pushurl" in source
193+
194+
if url.startswith("https://") and not has_pushurl:
195+
# HTTPS without pushurl: may need credentials, process serially
190196
https_packages.append(name)
191197
else:
198+
# SSH, fs, or HTTPS with pushurl: safe for parallel
192199
other_packages.append(name)
193200

194201
return https_packages, other_packages

tests/test_git_additional.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,3 +963,47 @@ def mock_run_git_side_effect(commands, **kwargs):
963963
with patch.object(wc, "git_version", return_value=(2, 30, 0)):
964964
with pytest.raises(GitError, match="git checkout"):
965965
wc.git_switch_branch("", "")
966+
967+
968+
def test_smart_threading_separates_https_with_pushurl():
969+
"""Test smart threading correctly separates HTTPS packages based on pushurl.
970+
971+
HTTPS URLs with pushurl should go to parallel queue (other_packages).
972+
HTTPS URLs without pushurl should go to serial queue (https_packages).
973+
"""
974+
from mxdev.vcs.common import WorkingCopies
975+
976+
sources = {
977+
"https-no-pushurl": {
978+
"name": "https-no-pushurl",
979+
"url": "https://github.com/org/repo1.git",
980+
"path": "/tmp/repo1",
981+
},
982+
"https-with-pushurl": {
983+
"name": "https-with-pushurl",
984+
"url": "https://github.com/org/repo2.git",
985+
"path": "/tmp/repo2",
986+
"pushurl": "git@github.com:org/repo2.git",
987+
},
988+
"ssh-url": {
989+
"name": "ssh-url",
990+
"url": "git@github.com:org/repo3.git",
991+
"path": "/tmp/repo3",
992+
},
993+
"fs-url": {
994+
"name": "fs-url",
995+
"url": "/local/path/repo4",
996+
"path": "/tmp/repo4",
997+
},
998+
}
999+
1000+
wc = WorkingCopies(sources=sources, threads=4, smart_threading=True)
1001+
packages = ["https-no-pushurl", "https-with-pushurl", "ssh-url", "fs-url"]
1002+
1003+
https_pkgs, other_pkgs = wc._separate_https_packages(packages)
1004+
1005+
# Only HTTPS without pushurl should be in serial queue
1006+
assert https_pkgs == ["https-no-pushurl"]
1007+
1008+
# HTTPS with pushurl, SSH, and fs should be in parallel queue
1009+
assert set(other_pkgs) == {"https-with-pushurl", "ssh-url", "fs-url"}

0 commit comments

Comments
 (0)