coder / coder/registry

rfc(git-clone): add support for pull request and merge request urls

Open
#67 2 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.