Skip to content

feat!: add repos.getCloneCredentials - #12

Merged
robingenz merged 1 commit into
mainfrom
feat/get-clone-credentials
Sep 4, 2026
Merged

feat!: add repos.getCloneCredentials#12
robingenz merged 1 commit into
mainfrom
feat/get-clone-credentials

Conversation

@robingenz

@robingenz robingenz commented Sep 4, 2026

Copy link
Copy Markdown
Member

Adds repos.getCloneCredentials, the clone credential returned separately from the URL, for consumers that hand credentials to a git credential helper instead of embedding them in the remote URL. Today the only way to get one is repos.getCloneUrl, which forces consumers to parse the userinfo back out of the URL and percent-decode it.

CloneCredentials is { expiresAt?, password, url, username }: url never carries userinfo, username and password are raw (never percent-encoded), password is null where the provider puts the token in the username slot (Gitea) or access is anonymous (git-http without auth), and username is null for anonymous access. Provider usernames are unchanged (x-access-token, oauth2, pat, x-bitbucket-api-token-auth, x-token-auth), and expiresAt is still set where it was before (GitHub App installation tokens).

Also:

  • getCloneUrl keeps its exact contract and is now derived: every provider builds credentials, and the new toCloneUrl helper in src/providers/shared.ts embeds them as percent-encoded userinfo, one URL builder instead of six per-provider string templates. GitLab's injectCredentials is gone.
  • GitLab's numeric-project-id path still resolves http_url_to_repo through the API; git-http still normalizes and rejects credential-bearing remote URLs.
  • Documents the method next to getCloneUrl in docs/guides/downloading-code.mdx, plus the namespace overview, the README "API at a glance" table and the README/CLAUDE.md redaction-exception note.
  • Adds 12 tests, one getCloneCredentials block per provider: password-slot token, Gitea's username-slot token, GitLab numeric id, Azure pat vs oauth2, Bitbucket's two usernames, git-http anonymous, expiresAt propagation, and that url carries no userinfo.

BREAKING CHANGE: getCloneCredentials is a new required method on the RepoProvider interface. Custom provider implementations must add it; the built-in providers already do. getCloneUrl can be derived from it with toCloneUrl semantics: embed username and password as percent-encoded userinfo in url.

Copilot AI lite review requested due to automatic review settings September 4, 2026 06:23
@robingenz robingenz added the feature Feature label Sep 4, 2026
@robingenz robingenz self-assigned this Sep 4, 2026

Copilot AI 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.

🟡 Changes recommended

The shared toCloneUrl implementation and the exported RepoProvider interface change introduce correctness/backcompat risks that should be addressed before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds a new repos.getCloneCredentials API to return clone credentials separately from a credential-free clone URL, and refactors providers so getCloneUrl is derived from these credentials via a shared helper. This fits the SDK’s normalized-provider design by offering a safer integration path for git credential helpers while keeping the existing clone-URL functionality.

Changes:

  • Introduces CloneCredentials / GetCloneCredentialsParams and wires repos.getCloneCredentials through the client + provider interface.
  • Refactors all providers to implement getCloneCredentials and derives getCloneUrl via the new shared toCloneUrl helper.
  • Adds provider/unit tests and updates docs/README/CLAUDE.md to document the new method and credential redaction exceptions.
File summaries
File Description
test/unit/client.test.ts Updates the unit test fake RepoProvider to include getCloneCredentials.
test/providers/testing.test.ts Adds in-memory provider coverage for client.repos.getCloneCredentials.
test/providers/gitlab.test.ts Adds GitLab getCloneCredentials tests, including numeric project ID behavior.
test/providers/github.test.ts Adds GitHub getCloneCredentials test.
test/providers/github-app.test.ts Adds GitHub App installation token + expiresAt propagation test for clone credentials.
test/providers/gitea.test.ts Adds Gitea token-in-username-slot clone-credentials test.
test/providers/git-http.test.ts Adds anonymous + basic-auth clone-credentials tests for git-http.
test/providers/bitbucket.test.ts Adds Bitbucket clone-credentials tests for API token vs access token auth.
test/providers/azure-devops.test.ts Adds Azure DevOps clone-credentials tests for PAT vs OAuth.
src/types.ts Adds CloneCredentials + GetCloneCredentialsParams; extends RepoProvider with getCloneCredentials.
src/providers/testing/index.ts Implements getCloneCredentials for the in-memory provider; derives getCloneUrl via helper.
src/providers/shared.ts Adds toCloneUrl helper to embed credentials into a credential-free URL.
src/providers/gitlab/index.ts Implements getCloneCredentials; derives getCloneUrl via toCloneUrl; removes GitLab-specific injector.
src/providers/github/index.ts Implements getCloneCredentials; derives getCloneUrl via toCloneUrl.
src/providers/gitea/index.ts Implements getCloneCredentials; derives getCloneUrl via toCloneUrl.
src/providers/git-http/index.ts Implements getCloneCredentials; derives getCloneUrl via toCloneUrl.
src/providers/bitbucket/index.ts Implements getCloneCredentials; derives getCloneUrl via toCloneUrl.
src/providers/azure-devops/index.ts Implements getCloneCredentials; derives getCloneUrl via toCloneUrl.
src/index.ts Exports the new types (CloneCredentials, GetCloneCredentialsParams).
src/client.ts Exposes repos.getCloneCredentials on the public client API.
README.md Updates “API at a glance” and the credential-redaction exception note to include getCloneCredentials.
docs/guides/downloading-code.mdx Documents repos.getCloneCredentials and warns to treat returned credentials as secrets.
docs/concepts/client-and-providers.mdx Updates the repos namespace overview list to include getCloneCredentials.
CLAUDE.md Updates the redaction exception note to include getCloneCredentials.
Review details
  • Files reviewed: 24/24 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/types.ts
Comment on lines +338 to 340
getCloneCredentials(params: GetCloneCredentialsParams): Promise<CloneCredentials>;
/** The same credentials embedded in the URL; derived from `getCloneCredentials`. */
getCloneUrl(params: GetCloneUrlParams): Promise<CloneUrl>;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agreed, this does break custom RepoProvider implementations. Rather than making the method optional with a URL-parsing fallback, which would reintroduce the parsing this PR removes, the PR is now marked as a breaking change (feat!: plus a BREAKING CHANGE: footer) so release-please bumps the minor version and records it in the changelog.

Comment thread src/providers/shared.ts
Comment on lines +48 to +54
export function toCloneUrl(credentials: CloneCredentials): CloneUrl {
const { expiresAt, password, url, username } = credentials;
if (username === null && password === null) return { url, expiresAt };
const user = username === null ? '' : encodeURIComponent(username);
const userinfo = password === null ? user : `${user}:${encodeURIComponent(password)}`;
return { url: url.replace('://', `://${userinfo}@`), expiresAt };
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Skipping. toCloneUrl is internal (not exported from the package entry) and its only callers are the built-in providers, which construct the credential-free url themselves, so the invariant holds by construction. The URL API would not reject the username: null plus password shape either, and its setters use a different percent-encoding set and normalize the URL, which would change the existing getCloneUrl output this PR keeps unchanged.

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Deploy preview available at: https://be1e845d.repo-sdk-page.pages.dev.

Built with commit 186bee3.

@robingenz robingenz changed the title feat: add repos.getCloneCredentials feat!: add repos.getCloneCredentials Sep 4, 2026
@robingenz
robingenz merged commit 08bdb50 into main Sep 4, 2026
5 checks passed
@robingenz
robingenz deleted the feat/get-clone-credentials branch September 4, 2026 08:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants