rfc(git-clone): add support for pull request and merge request urls
- Dominant language
- HCL
- Stars
- 79
- Forks
- 161
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 38
Description
# Overview
When building an "open in coder" workflow from any url, we could also support Github Pull Requests and Gitlab Merge Requests.
# Notes on Pull Request
Neither can allow for pushes to go to the right branch
Github:
- `git fetch origin pull//head:pr/; git switch pr/`
- `git fetch origin merge-requests//head; git switch FETCH_HEAD`
eg:
```bash
git clone https://github.com/michaelbrewer/repo-tests.log.git
cd repo-tests.log
git fetch origin pull/1/head:pr/1
git switch pr/1
```
Gitlab:
- `git fetch origin merge-requests//head:pr/; git switch pr/`
- `git fetch origin merge-requests//head; git checkout FETCH_HEAD`
eg:
```bash
git clone https://gitlab.com/mike.brew/repo-tests.log.git
cd repo-tests.log
git fetch origin merge-requests/1/head:mr/1
git switch mr/1
```
So probably better to use the github / gitlab apis?
# Using apis
To be able to support `git push` for a pull request, the most reliable way is to use the git providers api. We would need
to detect self-hosted git and find the relavant api endpoint ie: `https://api.github.com/` becomes `https://github.yourcompany.com/`
## Using the Github APIs:
We can setup the `origin` and `upstream` and get the correct branch name
```bash
#!/bin/bash
# Github Pull Request Cloning Script
# Example usage:
# export GITHUB_PAT=XXXX
# ./github-pr.sh https://github.com/coder/modules/pull/210
# ./github-pr.sh https://github.com/michaelbrewer/repo-tests.log/pull/1
url="$1"
owner=$(echo "$url" | cut -d'/' -f4)
repo=$(echo "$url" | cut -d'/' -f5)
pull_number=$(echo "$url" | cut -d'/' -f7)
output=$(curl -s -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_PAT" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/"$owner"/"$repo"/pulls/"$pull_number")
name=$(echo "$output" | jq -r '.base.repo.name')
clone_url=$(echo "$output" | jq -r '.head.repo.clone_url')
branch_name=$(echo "$output" | jq -r '.head.ref')
upstream_url=$(echo "$output" | jq -r '.base.repo.clone_url')
git clone "$clone_url" -b "$branch_name" "$name"
cd "$name" || exit
git remote add upstream "$upstream_url"
```
## Gitlab api
Gitlab version has to do 3 api calls and `id` is a best guess
```bash
#!/bin/bash
# Github Merge Request Cloning Script
#
# Example usage:
# GITLAB_PAT=XXXX
# ./gitlab-mr.sh https://gitlab.com/mike.brew/repo-tests.log/-/merge_requests/1
url="$1"
id=$(echo "$url" | cut -d'/' -f4,5 | sed 's/\//%2F/g')
merge_request_iid=$(echo "$url" | cut -d'/' -f8)
# Get the merge request details
# "GET /projects/$id/merge_requests/$merge_request_iid"
mr_output=$(curl -s -L \
-H "Accept: application/json" \
-H "Authorization: Bearer $GITLAB_PAT" \
https://gitlab.com/api/v4/projects/"$id"/merge_requests/"$merge_request_iid")
source_project_id=$(echo "$mr_output" | jq -r '.source_project_id')
target_project_id=$(echo "$mr_output" | jq -r '.target_project_id')
# Get the source project details
source_output=$(curl -s -L \
-H "Accept: application/json" \
-H "Authorization: Bearer $GITLAB_PAT" \
https://gitlab.com/api/v4/projects/"$source_project_id")
# Get the target project details
target_output=$(curl -s -L \
-H "Accept: application/json" \
-H "Authorization: Bearer $GITLAB_PAT" \
https://gitlab.com/api/v4/projects/"$target_project_id")
name=$(echo "$target_output" | jq -r '.name')
clone_url=$(echo "$source_output" | jq -r '.http_url_to_repo')
upstream_url=$(echo "$target_output" | jq -r '.http_url_to_repo')
branch_name=$(echo "$mr_output" | jq -r '.source_branch')
git clone "$clone_url" -b "$branch_name" "$name"
cd "$name" || exit
git remote add upstream "$upstream_url"
```
## Using Bitbucket API
From [Get a pull request
](https://developer.atlassian.com/cloud/bitbucket/rest/api-group-pullrequests/#api-repositories-workspace-repo-slug-pullrequests-pull-request-id-get
)
```bash
#!/bin/bash
# Bitbucket Pull Request Cloning Script
# Example usage:
# ./bitbucket-pr.sh https://bitbucket.org/gyftteam/repo-tests.log/pull-requests/1
BITBUCKET_PAT="username:app_password"
url="$1"
workspace=$(echo "$url" | cut -d'/' -f4)
repo_slug=$(echo "$url" | cut -d'/' -f5)
pull_request_id=$(echo "$url" | cut -d'/' -f7)
# Get the pull request details
output=$(curl -s --request GET \
--url "https://api.bitbucket.org/2.0/repositories/$workspace/$repo_slug/pullrequests/$pull_request_id" \
--header "Authorization: Basic $(echo -n $BITBUCKET_PAT | base64)" \
--header 'Accept: application/json')
# Get the source repo details
source_respotory_links_self=$(echo "$output" | jq -r '.source.repository.links.self.href')
source_output=$(curl -s --request GET \
--url "$source_respotory_links_self" \
--header "Authorization Basic $(echo -n $BITBUCKET_PAT | base64)" \
--header 'Accept: application/json')
# Get the target repo details
destination_respotory_links_self=$(echo "$output" | jq -r '.destination.repository.links.self.href')
destination_output=$(curl -s --request GET \
--url "$destination_respotory_links_self" \
--header "Authorization Basic $(echo -n $BITBUCKET_PAT | base64)" \
--header 'Accept: application/json')
name=$(echo "$output" | jq -r '.source.repository.name')
clone_url=$(echo "$source_output" | jq -r '.links.clone[] | select(.name == "https") | .href')
branch_name=$(echo "$output" | jq -r '.source.branch.name')
upstream_url=$(echo "$destination_output" | jq -r '.links.clone[] | select(.name == "https") | .href')
git clone "$clone_url" -b "$branch_name" "$name"
cd "$name" || exit
git remote add upstream "$upstream_url"
```
Contributor guide
Assessment
This issue has not been assessed yet.