Skip to content

feat(push): Allow push-remote to be a remote's URL - #1022

Open
cowlicks wants to merge 1 commit into
crate-ci:mainfrom
cowlicks:gh-1007
Open

cowlicks wants to merge 1 commit into
crate-ci:mainfrom
cowlicks:gh-1007

Conversation

@cowlicks

@cowlicks cowlicks commented Oct 5, 2026

Copy link
Copy Markdown

Remote names differ between clones (e.g. origin vs upstream in a fork workflow), so a shared release.toml can't reliably name the push target.

push-remote may now be a URL. It is resolved to the configured remote whose url or pushurl matches, ignoring scheme, user, port, a trailing .git, and host case, so https and ssh forms of the same repo match. If no remote matches, we error early and list the configured remotes; if several match, we error and name them. Values without a : are still treated as remote names, unchanged.

Fixes #1007

What does this PR try to solve?

Closes #1007

The push-remote in releas.toml currently only accepts a remote name. As discussed in #1007 names differ between clones, so in a workflow one person's origin or upstream might not actually point to the git repo which the projects release is supposed to target. This PR lets push-remote (and --push-remote) accept a URL, the repository can be addressed in a universally unique way.

push-remote = "https://github.com/crate-ci/cargo-release"

The URL is must resolve to local git remote whose url or pushurl matches it. So a remote listed in git remote -v must match the provided URL. Then everything after that works on that remote's name as before.
In the related issue we discussed having git push to a URL, and detecting a URL vs remote name. By resolving the URL to a remote name, we don't need to worry about pushing to a URL. As for detecting URLs, we just check for : in the push-remote string. This works because: git remotes cannot contain : and (I'm 99% sure) the URLs for git remotes always contain a :.

Behavior:

There are a few cases to consider. The existing behavior: this happens whenever there is no : in push-remote. New behavior happens when there is a : and this has a few cases:

  • No remote is matched: the release fails before anything is modified. The error lists the configured remotes and suggests git remote add:
    error: push-remote `https://example.com/nope` is neither a remote name nor the URL of a configured remote
           configured remotes:
             origin  git@github.com:me/demo.git
             upstream  https://github.com/example/demo
           to add it, run `git remote add <name> https://example.com/nope`
    
  • A single remote matches: the remote name is passed through and everything proceeds as before.
  • Multiple remotes match: the release fails, and the error names the matching remotes.

Resolution only happens when pushing is enabled, so --no-push is unaffected.

Notes to reviewers

  • The URL parsing in normalize_url in src/ops/git.rs, written that way to avoid adding a url/gix-url dependency. Local paths and file:// URLs aren't normalized and fall back to an exact string match.
  • The path part of a URL is matched with case-sensitivity. Github ignores case in paths, but other hosts might not, so I kept it strict. I'm happy to relax it if you'd prefer.
  • Tests: unit tests cover URL normalization (equivalent https/ssh/scp forms, local paths) and resolution against a temp repo (by name, by url, by pushurl only, a missing name passed through, an unknown URL, and an ambiguous URL).
  • Manual testing: dry runs in a scratch repo with origin and upstream remotes, using the https and scp forms of the upstream URL, the name upstream, and an unknown URL. There was no existing machinery in the tests for stuff like this so I did it manually.

LLM stuff: I used Claude Code to understand the repo, plan approach, and to write the unit tests.

Remote names differ between clones (e.g. `origin` vs `upstream` in a fork
workflow), so a shared `release.toml` can't reliably name the push target.

`push-remote` may now be a URL. It is resolved to the configured remote
whose `url` or `pushurl` matches, ignoring scheme, user, port, a trailing
`.git`, and host case, so https and ssh forms of the same repo match. If no
remote matches, we error early and list the configured remotes; if several
match, we error and name them. Values without a `:` are still treated as
remote names, unchanged.

Fixes crate-ci#1007

This branch has not been deployed

No deployments
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.

Allow setting push-remote=... to a git URL, not just a remote name

1 participant