Skip to content

fix: preserve ssh:// dependency URLs for Bitbucket Datacenter repositories#665

Open
edenfunf wants to merge 4 commits intomicrosoft:mainfrom
edenfunf:fix/preserve-ssh-url-bitbucket-datacenter
Open

fix: preserve ssh:// dependency URLs for Bitbucket Datacenter repositories#665
edenfunf wants to merge 4 commits intomicrosoft:mainfrom
edenfunf:fix/preserve-ssh-url-bitbucket-datacenter

Conversation

@edenfunf
Copy link
Copy Markdown
Contributor

Fixes #661.

Root Cause

When APM parses a dependency URL that starts with ssh://, _normalize_ssh_protocol_url converts it to the git@host:path format and silently drops any custom port:

ssh://git@bitbucket.domain.ext:7999/project/repo.git
→ git@bitbucket.domain.ext:project/repo.git   (port 7999 gone)

_clone_with_fallback then tries SSH on the reconstructed URL (default port 22, wrong) which fails, and falls back to:

https://bitbucket.domain.ext/project/repo   ← not what the user asked for

This affects Bitbucket Datacenter and any other self-hosted git server that uses a non-standard SSH port.

Fix

Add an original_ssh_url field to DependencyReference. When parse_from_str encounters a URL that begins with ssh://, the verbatim string is stored in this field before the normalisation step.

In _clone_with_fallback, Method 2 (SSH) now uses dep_ref.original_ssh_url directly when it is set, instead of rebuilding the URL from host + repo_ref (which loses the port):

if dep_ref and dep_ref.original_ssh_url:
    ssh_url = dep_ref.original_ssh_url      # exact user-supplied URL
else:
    ssh_url = self._build_repo_url(...)     # existing behaviour

Before

ssh://git@bitbucket.domain.ext:7999/project/repo.git
→ git clone ... https://bitbucket.domain.ext/project/repo   ❌

After

ssh://git@bitbucket.domain.ext:7999/project/repo.git
→ git clone ... ssh://git@bitbucket.domain.ext:7999/project/repo.git   ✅

Changes

File Change
src/apm_cli/models/dependency/reference.py Add original_ssh_url dataclass field; capture it in parse_from_str before normalisation; pass to constructor
src/apm_cli/deps/github_downloader.py Use dep_ref.original_ssh_url verbatim in SSH clone attempt when present
tests/unit/test_generic_git_urls.py New TestBitbucketDatacenterSSH class with 5 regression tests

Regression Protection

Added TestBitbucketDatacenterSSH covering:

  • ssh:// with custom port stores the original URL in original_ssh_url
  • Host and repo_url fields are still correctly parsed
  • ssh:// without a port also preserves the original URL
  • HTTPS URLs do not set original_ssh_url
  • git@ shorthand URLs do not set original_ssh_url

All 3 763 existing unit tests continue to pass.

Fixes microsoft#661. When a user specifies an explicit ssh:// URL in apm.yml
(e.g. ssh://git@bitbucket.domain.ext:7999/project/repo.git), APM was
silently stripping the port during ssh:// → git@ normalisation and then
falling back to https:// after the portless SSH clone attempt failed.

Store the original ssh:// string in DependencyReference.original_ssh_url
before normalisation, and pass it verbatim to git clone in
_clone_with_fallback so the port and protocol are preserved.
Copy link
Copy Markdown
Collaborator

@sergio-sisternes-epam sergio-sisternes-epam left a comment

Choose a reason for hiding this comment

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

Clean, focused fix — the "preserve original URL, don't fix normalization" approach is the right call. Minimal risk, no side effects on existing URL handling. The PR description is excellent with clear root cause analysis and before/after examples.

The test coverage is thorough: custom port, standard ssh, https exclusion, git@ exclusion, and clone URL ordering all covered.

One request before merge: please add a CHANGELOG entry under ## [Unreleased]:

### Fixed
- Preserve `ssh://` dependency URLs with custom ports for Bitbucket Datacenter repositories instead of silently falling back to HTTPS (#661)

Thanks for another solid contribution!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes cloning failures for self-hosted Git servers (notably Bitbucket Datacenter) when dependencies are specified with an explicit ssh://...:PORT/... URL by preserving the original SSH URL and using it for the SSH clone attempt.

Changes:

  • Add DependencyReference.original_ssh_url and populate it when parsing ssh:// dependency strings.
  • Update _clone_with_fallback to prefer original_ssh_url for the SSH clone method.
  • Add regression tests covering parsing and clone URL selection for ssh:// URLs with custom ports.
Show a summary per file
File Description
src/apm_cli/models/dependency/reference.py Adds original_ssh_url and captures it during parsing for ssh:// inputs.
src/apm_cli/deps/github_downloader.py Uses original_ssh_url directly for the SSH clone attempt to preserve custom ports.
tests/unit/test_generic_git_urls.py Adds parsing regression tests for Bitbucket Datacenter-style ssh:// URLs with ports.
tests/unit/test_auth_scoping.py Adds downloader regression tests to assert the SSH clone attempt uses the original ssh:// URL verbatim.

Copilot's findings

  • Files reviewed: 4/4 changed files
  • Comments generated: 3

Raw dependency strings can include '#ref' or '@alias' suffixes which are
not valid git clone URL syntax. Strip these from original_ssh_url at capture
time so the port-preserving clone path does not silently fail and re-trigger
the https fallback.

Also narrows the over-broad except clause in regression tests from
(RuntimeError, Exception) to (RuntimeError, GitCommandError), and adds the
CHANGELOG entry requested in review.
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.

[BUG] Ignores ssh://, tries https (Bitbucket Datacenter)

4 participants