Skip to content

fix(cloud-manager-client): build PR URL for Azure DevOps and Bitbucket#1793

Open
rpapani wants to merge 3 commits into
mainfrom
fix/cm-client-pr-url-azure-bitbucket
Open

fix(cloud-manager-client): build PR URL for Azure DevOps and Bitbucket#1793
rpapani wants to merge 3 commits into
mainfrom
fix/cm-client-pr-url-azure-bitbucket

Conversation

@rpapani

@rpapani rpapani commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Problem

CloudManagerClient#createPullRequest only constructed a pullRequestUrl for GitHub and GitLab. For Azure DevOps and Bitbucket BYOG repos, #buildPullRequestUrl fell through to null, so pullRequestUrl was never set — even though the CM Repo API had actually created the PR (and returned its externalNumber).

Downstream, spacecat-autofix-worker's CodeRepoManager then stored an empty changeDetails.pullRequestUrl, so the CWV Deployed tab in ASO UI showed no "View PR" link for those repos.

This was never an intentional restriction — PR #1371 simply implemented GitHub/GitLab as the providers needed at the time.

Change

Add PR/MR path templates + host detection for the two missing providers:

Provider Host match Path
Azure DevOps dev.azure.com, *.visualstudio.com /pullrequest/{n}
Bitbucket Cloud bitbucket.org /pull-requests/{n}

Unknown hosts still return null (unchanged). Both CM_REPO_TYPE.AZURE_DEVOPS and CM_REPO_TYPE.BITBUCKET already existed in the enum.

Tests

Added unit tests for both new providers (incl. legacy visualstudio.com) and repointed the "unsupported provider" test at a generic host. Package stays at 100% coverage (90 passing).

🤖 Generated with Claude Code

rpapani and others added 2 commits July 8, 2026 11:32
`createPullRequest` constructed a pullRequestUrl only for GitHub and
GitLab; for Azure DevOps and Bitbucket BYOG repos the provider detection
fell through to null, so `pullRequestUrl` was never set even though the CM
Repo API had actually created the PR (and returned its externalNumber).
Downstream (spacecat-autofix-worker CodeRepoManager) then stored an empty
`changeDetails.pullRequestUrl`, so the CWV "Deployed" tab showed no
"View PR" link for those repos.

Add path templates + host detection for:
  - Azure DevOps (dev.azure.com / *.visualstudio.com) -> /pullrequest/{n}
  - Bitbucket Cloud (bitbucket.org)                    -> /pull-requests/{n}

Unknown hosts still return null (unchanged). Adds unit tests for both new
providers and repoints the "unsupported provider" test at a generic host;
package stays at 100% coverage.

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

This PR will trigger a patch release when merged.

@rpapani rpapani requested a review from ramboz July 8, 2026 23:44
createPullRequest issued a single POST and threw on any non-2xx, with no
retry — a brief 5xx/429 or network blip from the CM Repo API would fail the
whole autofix PR. Add one retry after a short wait (1.5s) for transient
failures only; permanent failures (4xx other than 429) still throw
immediately. The transient failure + retry is logged (log.warn).

Adds tests for transient-5xx-then-success, network-error-then-success, and
two-consecutive-transient-failures (throws after 2 attempts). Package stays
at 100% coverage.

Co-Authored-By: Claude <noreply@anthropic.com>

@ramboz ramboz left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

PR Review: fix(cloud-manager-client): build PR URL for Azure DevOps and Bitbucket

Summary

Adds Azure DevOps + Bitbucket Cloud provider detection and PR/MR path templates to #buildPullRequestUrl, and — not mentioned in the description — wraps the CM PR-creation fetch in a single-retry loop for transient (5xx / 429 / network) failures. The logic is correct, backward-compatible, and well-tested. Ready to merge; the one Should-Fix is doc-only.

This is one half of a cross-repo effort with adobe/spacecat-autofix-worker#666: this client must be released to npm first, then #666 bumps the dep. #666 relies on the new Azure/Bitbucket URL building here so the CWV "View PR" link renders for those BYOG repos, and the retry added here reduces how often #666's "branch pushed, PR failed" path is hit.

Strengths

  • The retry loop is carefully written. Permanent 4xx (except 429) throw immediately; transient 5xx/429 and thrown fetches (network/timeout) retry once; exhaustion throws a distinct ...failed after N attempts message. The if (response && !transient) guard correctly distinguishes a re-thrown permanent HTTP error from a network throw, and every attempt-2 path either breaks or throws — so the loop can never fall through to response.json() with an undefined/non-ok response.
  • #PR_PATH_BY_PROVIDER is a clean frozen lookup table; unknown hosts still return null, so there is no regression for providers CM doesn't map.
  • Good, targeted test coverage: all four providers (incl. legacy visualstudio.com), transient-5xx-then-success, network-error-then-success, and two-transient-then-throw.

Issues

Blockers (Must Fix Before Merge)

None.

Should Fix

S1. PR description + commit subject omit the retry behaviorpackages/spacecat-shared-cloud-manager-client/src/index.js
The title/body only describe the provider URL additions, but the diff also adds a single-retry loop to createPullRequest. That is a real behavior change for all callers of this shared method (eds-csp, accessibility, vulnerabilities, cwv): up to ~1.5s extra latency on a transient failure, plus a changed thrown-error message format (HTTP <status> - ... and ...failed after 2 attempts: ...). Since merging triggers a patch release, the semantic-release changelog — generated from the commit subject — will not mention the retry. Please update the PR body/commit subject so the shipped behavior is captured.
Perspective: Engineering Practices / Product

Nice to Have

N1. The 422 test doesn't guard the no-retry-on-4xx contractpackages/spacecat-shared-cloud-manager-client/test/cloud-manager-client.test.js:1945
it('throws on failed PR creation') uses a single nock interceptor and asserts rejectedWith('Pull request creation failed'). That matcher is a prefix that also matches the retry-exhausted message Pull request creation failed after 2 attempts, and there's no scope.isDone() assertion — so a regression that retried a 4xx would still pass this test. Consider asserting expect(scope.isDone()).to.be.true (proving exactly one request) or matching the exact Pull request creation failed: HTTP 422 message.
Perspective: QA / Testing

N2. Host detection via substring includes() — see inline comment. Pre-existing pattern extended to the new providers; low risk. Noted inline.
Perspective: Architecture

Verdict

Ready to merge: Yes (approving) — address S1 (description) before/at merge so the release notes are accurate.
Reasoning: Correct, backward-compatible, well-tested; the only Should-Fix is documentation of a shipped behavior change.


Note: reviewed against the PR branch with full repo context. I did not execute the test suite locally (monorepo node_modules not installed); relying on CI + static analysis. No downstream code in the sibling repos string-matches the old error message, so the message-format change is safe.

provider = CM_REPO_TYPE.GITHUB;
} else if (repoUrl.includes('gitlab.com') || repoUrl.includes('gitlab.')) {
provider = CM_REPO_TYPE.GITLAB;
} else if (repoUrl.includes('dev.azure.com') || repoUrl.includes('visualstudio.com')) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

N2 (nice-to-have): provider detection uses substring includes(), so a repoUrl whose path contains a provider domain (e.g. https://bitbucket.org/team/github.com-mirror) can be misclassified — the checks are ordered, so github.com would win here. This is the pre-existing pattern (github/gitlab already do it) just extended, and the risk is low: repoUrl comes from the customer's CM config and the worst case is a wrong PR-URL label. Worth hardening later by parsing the hostname. Also note bitbucket.org intentionally won't match self-hosted Bitbucket Server/Data Center (different path shape) — fine given the PR targets Bitbucket Cloud, just flagging the boundary.

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