Closed19

ghq で CodeCommit HTTPS (GRC) 形式をサポートする改修作業

XeresXeres

作業環境。

$ ghq version 1.1.7 (rev:7f31419)
$ pipx list | grep git-remote-codecommit
   package git-remote-codecommit 1.15.1, Python 3.8.8
    - git-remote-codecommit

最新の ghq が素の状態で HTTPS (GRC) 形式が利用できるか確認する。

確認する HTTPS (GRC) 形式は Setup steps for HTTPS connections to AWS CodeCommit with git-remote-codecommit - AWS CodeCommit にサンプルとして記載されているもの3つ。

  • codecommit://MyDemoRepo
  • codecommit://CodeCommitProfile@MyDemoRepo
  • codecommit::ap-northeast-1://MyDemoRepo

まず、codecommit://MyDemoRepo 形式から。

$ ghq get codecommit://MyDemoRepo
     clone codecommit://MyDemoRepo -> /home/xeres/repos/MyDemoRepo
     error failed to get "codecommit://MyDemoRepo": unsupported VCS, url=codecommit://MyDemoRepo: Get "codecommit://MyDemoRepo?go-get=1": unsupported protocol scheme "codecommit"

VCS および URL scheme が不明だと怒られるので、まず VCS を明示的に指定してみる。

$ ghq get --vcs git codecommit://MyDemoRepo
     clone codecommit://MyDemoRepo -> /home/xeres/repos/MyDemoRepo
       git clone --recursive codecommit://MyDemoRepo /home/xeres/repos/MyDemoRepo
Cloning into '/home/xeres/repos/MyDemoRepo'...
The following profile does not have an AWS Region: default. You must set an AWS Region for this profile. For more information, see Configure An AWS CLI Profile in the AWS CLI User Guide.
     error failed to get "codecommit://MyDemoRepo": /usr/bin/git: exit status 128

お、なにか git-remote-codecommit を呼び出しているようだ。

独自 URL scheme のサポートについて体系的なドキュメントは見つけられなかったが、git/git/Documentation/config/remote.txt を見ると、git-remote-<scheme> の命名規則でヘルパースクリプトを作ればいいっぽい。

AWS CLI のプロファイル設定を済ませた上で、再度コマンドを実行してみる。なお、この時点では CodeCommit リポジトリは作成していない。

$ export AWS_PROFILE=main
$ ghq get --vcs git codecommit://MyDemoRepo
     clone codecommit://MyDemoRepo -> /home/xeres/repos/MyDemoRepo
       git clone --recursive codecommit://MyDemoRepo /home/xeres/repos/MyDemoRepo
Cloning into '/home/xeres/repos/MyDemoRepo'...
fatal: repository 'https://git-codecommit.us-east-1.amazonaws.com/v1/repos/MyDemoRepo/' not found
     error failed to get "codecommit://MyDemoRepo": /usr/bin/git: exit status 128

対象の HTTPS 形式のリポジトリ名が出力されているので AWS CLI プロファイルは機能している模様。git clone 先が $GHQ_ROOT/MyDemoRepo になっているのが気になる。一旦、この点は脇に置いて、空の CodeCommit リポジトリを作成して再度 git clone してみる。

$ export AWS_PROFILE=main
$ ghq get --vcs git codecommit://MyDemoRepo
     clone codecommit://MyDemoRepo -> /home/xeres/repos/MyDemoRepo
       git clone --recursive codecommit://MyDemoRepo /home/xeres/repos/MyDemoRepo
Cloning into '/home/xeres/repos/MyDemoRepo'...
warning: You appear to have cloned an empty repository.
$ ghq list
MyDemoRepo
github.com/xeres/chezmoi

問題なく動作した。

次に codecommit://CodeCommitProfile@MyDemoRepo を確認する。

$ unset AWS_PROFILE
$ ghq get --vcs git codecommit://main@MyDemoRepo
    exists /home/xeres/repos/MyDemoRepo
$ rm -rf ~/repos/MyDemoRepo/
$ ghq get --vcs git codecommit://main@MyDemoRepo
     clone codecommit://main@MyDemoRepo -> /home/xeres/repos/MyDemoRepo
       git clone --recursive codecommit://main@MyDemoRepo /home/xeres/repos/MyDemoRepo
Cloning into '/home/xeres/repos/MyDemoRepo'...
warning: You appear to have cloned an empty repository.

こちらも問題なく動作した。

最後に codecommit::ap-northeast-1://MyDemoRepo 形式。プロファイルの region 指定とは異なるリージョンに CodeCommit リポジトリを作成して試行。

$ ghq get --vcs git codecommit::ap-northeast-1//MyDemoRepo2
     clone ssh://codecommit/:ap-northeast-1//MyDemoRepo2 -> /home/xeres/repos/codecommit/:ap-northeast-1/MyDemoRepo2
       git clone --recursive ssh://codecommit/:ap-northeast-1//MyDemoRepo2 /home/xeres/repos/codecommit/:ap-northeast-1/MyDemoRepo2
Cloning into '/home/xeres/repos/codecommit/:ap-northeast-1/MyDemoRepo2'...
ssh: Could not resolve hostname codecommit: Name or service not known
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
     error failed to get "codecommit::ap-northeast-1//MyDemoRepo2": /usr/bin/git: exit status 128

URL として codecommit::<region>://<repository> 形式が歪なので、上手く対応できない模様。

XeresXeres

ghq get さえ問題なく動作すれば、ghq list はできるので (.git フォルダの有無だけをチェックしているっぽい)、問題は codecommit::<region>://<repository> 形式のサポートと、codecommit:// 形式でのホスト名とリポジトリの取り扱いだなあ。

XeresXeres

x-motemen/ghq/url.go の 54 行目あたりを見た限り、net/url で URL をパースしているようなので、ここに手をいれるだけで改善できそう。

というわけで、golangnet/url の動作チェック。

FROM golang:latest
COPY . /go
ENTRYPOINT ["go", "run", "/go/main.go"]
main.go
package main

import (
    "flag"
    "net/url"
    "fmt"
    "log"
)

func main() {
    flag.Parse()
    for _, arg := range flag.Args() {
        u, err := url.Parse(arg)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("URL: %s\n", u.String())
        fmt.Printf("Scheme: %s\n", u.Scheme)
        fmt.Printf("Opaque: %s\n", u.Opaque)
        fmt.Printf("User: %s\n", u.User)
        fmt.Printf("Host: %s\n", u.Host)
        fmt.Printf("Path: %s\n", u.Path)
        fmt.Println()

        for key, values := range u.Query() {
            fmt.Printf("Query Key: %s\n", key)
            for i, v := range values {
                fmt.Printf("Query Value[%d]: %s\n", i, v)
            }
        }
    }
}

で、こうする。

$ docker build -t $(basename $PWD) .
(…以下中略…)
$ docker run $(basename $PWD) https://github.com/xeres/dotfiles codecommit://MyDemoRepo codecommit://CodeCommitProfile@MyDemoRepo codecommit::ap-northeast-1://MyDemoRepo
URL: https://github.com/xeres/dotfiles
Scheme: https
Opaque:
User:
Host: github.com
Path: /xeres/dotfiles

URL: codecommit://MyDemoRepo
Scheme: codecommit
Opaque:
User:
Host: MyDemoRepo
Path:

URL: codecommit://CodeCommitProfile@MyDemoRepo
Scheme: codecommit
Opaque:
User: CodeCommitProfile
Host: MyDemoRepo
Path:

URL: codecommit::ap-northeast-1://MyDemoRepo
Scheme: codecommit
Opaque: :ap-northeast-1://MyDemoRepo
User:
Host:
Path:

うん、まあ概ね予想通り。

codecommitLikeURLPatterncodecommit: で始まるリポジトリ指定を if 文で引っかけるようにして、URI.parse(ref) が下記のようになるように、URL を組み立ててやれば良さそう。

Scheme: codecommit
User: CodeCommitProfile
Host: git-codecommit.<region>.amazonaws.com
Path: MyDemoRepo
XeresXeres

aws/git-remote-codecommit/git_remote_codecommit/__init__.py の 68 行目を見る限り、codecommit::<region>://<profile>@<repository> 形式もサポートしないといけないみたい。

つまり、サポートが必要な形式は下記の 4 つ。

  • codecommit://MyDemoRepo
  • codecommit://CodeCommitProfile@MyDemoRepo
  • codecommit::ap-northeast-1://MyDemoRepo
  • codecommit::ap-northeast-1://CodeCommitProfile@MyDemoRepo

一応、試しておく。

$ ghq get --vcs git codecommit::ap-northeast-1//main@MyDemoRepo2
     clone ssh://codecommit/:ap-northeast-1//main@MyDemoRepo2 -> /home/xeres/repos/codecommit/:ap-northeast-1/main@MyDemoRepo2
       git clone --recursive ssh://codecommit/:ap-northeast-1//main@MyDemoRepo2 /home/xeres/repos/codecommit/:ap-northeast-1/main@MyDemoRepo2
Cloning into '/home/xeres/repos/codecommit/:ap-northeast-1/main@MyDemoRepo2'...
ssh: Could not resolve hostname codecommit: Name or service not known
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
     error failed to get "codecommit::ap-northeast-1//main@MyDemoRepo2": /usr/bin/git: exit status 128

$ docker run $(basename $PWD) codecommit::ap-northeast-1://CodeCommitProfile@MyDemoRepo
URL: codecommit::ap-northeast-1://CodeCommitProfile@MyDemoRepo
Scheme: codecommit
Opaque: :ap-northeast-1://CodeCommitProfile@MyDemoRepo
User:
Host:
Path:

ですよねー。

XeresXeres

一応。

.gitconfig (抜粋)
[ghq "codecommit://"]
vcs = git
$ export AWS_PROFILE=main
$ ghq get codecommit://MyDemoRepo
     clone codecommit://MyDemoRepo -> /home/xeres/repos/MyDemoRepo
       git clone --recursive codecommit://MyDemoRepo /home/xeres/repos/MyDemoRepo
Cloning into '/home/xeres/repos/MyDemoRepo'...
warning: You appear to have cloned an empty repository.

ヨシッ!

XeresXeres

Go での開発は初めて。普段 Go を使わないので、手元にビルド環境を入れたくないなというのでコンテナ化にチャレンジ。最初は golang - Docker Hub あたりを見ながら、雰囲気で Dockerfile を書いて全く動かず、ググるなど。

結局、この方の記事が参考になった。

【Golang】Alpine Docker で実行すると error: stdlib.h: No such file or directory. "stdlib.h" が足りないと言われる - Qiita

手元でビルド、動作確認をして PR が送ることができれば十分なので、こんな感じに。

Dockerfile
FROM golang:alpine

WORKDIR /app
COPY . .

RUN apk update && \
    apk add --no-cache alpine-sdk build-base && \
    go mod download && \
    go build

ENTRYPOINT ["./ghq"]

とりあえず、x-motemen/ghq を fork して clone して、Dockerfile を置いて、こうする。

$ docker build -t $(basename $PWD) .
[+] Building 1.3s (9/9) FINISHED
 => [internal] load build definition from Dockerfile
 => => transferring dockerfile: 38B
 => [internal] load .dockerignore
 => => transferring context: 2B
 => [internal] load metadata for docker.io/library/golang:alpine
 => [1/4] FROM docker.io/library/golang:alpine@sha256:4dd403b2e7a689adc5b7110ba9cd5da43d216cfcfccfbe2b35680effcf336c7e
 => [internal] load build context
 => => transferring context: 3.82kB
 => CACHED [2/4] WORKDIR /app
 => CACHED [3/4] COPY . .
 => CACHED [4/4] RUN apk update &&     apk add --no-cache alpine-sdk build-base &&     go mod download &&     go build
 => exporting to image
 => => exporting layers
 => => writing image sha256:f514cd5210e8d52be851cbedb4cca5d548b6ad662ee23dacb5579bde04fe055d
 => => naming to docker.io/library/ghq

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
$ docker run -t $(basename $PWD)
NAME:
   ghq - Manage remote repository clones

USAGE:
   ghq [global options] command [command options] [arguments...]

VERSION:
   1.1.7 (rev:HEAD)

AUTHORS:
   motemen <motemen@gmail.com>
   Songmu <y.songmu@gmail.com>

COMMANDS:
   get      Clone/sync with a remote repository
   list     List local repositories
   root     Show repositories' root
   create   Create a new repository
   help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help (default: false)
   --version, -v  print the version (default: false)

動いた。

他、cli/cli の設定をしたり、grex を試したりしているうちに時間切れ。

grex は、ちょっとしたツールを作るときにサンプルデータから正規表現が一発で生成できたら楽だな、と思って試してみた。しかし、プログラミング言語によって正規表現は異なるし、後方参照を利用する場合には、どうグループ化するかは自分で制御したいので、結局、自分で正規表現を考えたほうが早いという結論になった。

XeresXeres

x-motemen/ghq/url.go の 54 行目あたりを見た限り、net/url で URL をパースしているようなので、ここに手をいれるだけで改善できそう。

そんなふうに考えていた時期が俺にもありました

ローカルリポジトリのディレクトリを作るときに newURL した結果を使っているようなので、あとはこれを使いまわして色んな処理をしているのかと思ったら、あちこちで泥臭い処理をしていて、cmd_get.go, getter.go, remote_repository.go, vcs.go あたりも触らないとダメそう。辛い。どうせ git しか使わないし、車輪の再発名をしたほうが早いのでは、と思い始めた。

それはそれとして、git clone を裏で動かすところまでは行った。が、単純に docker run するだけでは不都合が出始めたので(具体的には $GHQ_ROOT/<aws_region>/<repos> あたりに読み書きしたい)、Remote Containers を初めて触ることに。

下記のクラメソさんの Blog が前提知識ゼロで始めるには参考になった。

https://dev.classmethod.jp/articles/vscode-remote-containers-golang/

後から見直すと、初めからここを読めば良かっただけだったけどw

https://code.visualstudio.com/docs/remote/containers

.devcontainer/devcontainer.json は自動生成されたものをそのまま使っている。

Dockerfile はデフォルトのものをベースに、git-remote-codecommit がないと話にならないので、とりあえずそれだけ入れている。他言語の開発でも Node.js を入れる必要があるのかどうか、よく分かっていない。

.devcontainer/Dockerfile
ARG VARIANT="1.16"
FROM mcr.microsoft.com/vscode/devcontainers/go:0-${VARIANT}

ARG INSTALL_NODE="true"
ARG NODE_VERSION="lts/*"
RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi

RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
    && apt-get -y install --no-install-recommends python3 python3-pip python3-setuptools \
    && pip3 install git-remote-codecommit

デバッグ時に ghq に引数を渡すために .vscode/launch.js も使っている。

.vscode/launch.js
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch: HTTP (GRC) Full Format",
            "type": "go",
            "request": "launch",
            "mode": "auto",
            "program": "${fileDirname}",
            "env": {},
            "args": ["get", "codecommit::us-east-1://main@MyDemoRepo"]
        }
    ]
}

なんか思ったより学習コストが低かったので、もっと早く試しておけばよかった。

仕事でやっている開発作業もこれを前提にすると相当楽になるなあ…と思いつつ、仕事では WorkSpaces で開発しているので、Nested Virtualization 環境で WSL2 が動作しないのが難点。

XeresXeres

RFC 3986 の Appendix B. Parsing a URI Reference with a Regular Expression を元にパース。

package main

import (
	"flag"
	"fmt"
	"regexp"
)

func main() {
	flag.Parse()
	for _, arg := range flag.Args() {
		var pattern = regexp.MustCompile(`^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?`)

		for i, v := range pattern.FindStringSubmatch(arg) {
			fmt.Printf("$%d: %s\n", i, v)
		}
		fmt.Println()
	}
}
$ go run ./main.go
$0: https://github.com/xeres/ghq
$1: https:
$2: https
$3: //github.com
$4: github.com
$5: /xeres/ghq
$6: 
$7: 
$8: 
$9: 

$0: codecommit::region://repository
$1: codecommit:
$2: codecommit
$3: 
$4: 
$5: :region://repository
$6: 
$7: 
$8: 
$9: 

$0: codecommit::region://profile@repository
$1: codecommit:
$2: codecommit
$3: 
$4: 
$5: :region://profile@repository
$6: 
$7: 
$8: 
$9: 

$0: codecommit://repository
$1: codecommit:
$2: codecommit
$3: //repository
$4: repository
$5: 
$6: 
$7: 
$8: 
$9: 

$0: codecommit://profile@repository
$1: codecommit:
$2: codecommit
$3: //profile@repository
$4: profile@repository
$5: 
$6: 
$7: 
$8: 
$9:

HTTP (GRC) の URLauthorityregion を入れるべきだったと思うけどなあ…。まあ、今更文句を付けても仕方がない。

ghq の中では net/urlURL クラスを使いまわしているので、HTTP (GRC) 用の URL 構造体を作らないとダメそう (パッと調べた感じ、Go には継承がない?らしいので後で調べる)。

XeresXeres

net/urlURL に相当するインターフェースがないので CodeCommitURL みたいなのは作れないっぽい。Go の interface は継承というよりは委譲なんだね。アップキャストも出来ないのかな。

RemoteRepository の方は interface 定義がされていたので、URL.Opaque に元 URL を入れておいて、URL に依存した処理で問題が出るところは if u.Scheme == "codecommit" { ... } してどうにかするというモンキーパッチで何とかした。

というか、ローカルリポジトリ周りの処理が URL にかなり依存していて厳しい。

RemoteRepository 側に $GHQ_ROOT/<relative-path><relative-path> を返すようなインターフェースを用意したほうがスマートかもしれない。ま、その辺は実装終わった後のリファクタリングで考えよう。

まずは必要な情報が URL から全て揃う codecommit::region://profile@repository 形式で ghq get codecommit::region://profile@repository 形式が動作することを確認。

なんとか動いた図

うおおおお!!!

XeresXeres

動作確認だけして、眠かったのと感動したのとで書き忘れた。

元のコードが linter に引っかかりまくって鬱陶しいので一部のルールをオフにする。流れているメッセージを見る限り、staticcheck なる linter が使われているらしい。色々調べた結果、VS Code や devcontainer.json の設定でオフにする方法はなさそう。仕方がないのでリポジトリ中に下記のファイルを置いて対応。このファイル自体は .devcontainer と同様に .git/info/exclude に書いて除外。

staticcheck.conf
checks = ["all", "-ST1005", "-SA4006", "-SA4021", "-SA4000", "-SA6005"]

参考URL: https://zenn.dev/sanpo_shiho/articles/09d1da9af91998
参考URL: https://github.com/golang/go/issues/38968


git-remote-codecommit~/.aws/config の AWS CLI プロファイル設定に依存しているため、devcontainer.json に下記のような設定を追加して、AWS CLI の設定だけマウントした。

devcontainer.json (抜粋
	"mounts": [
		"source=${localEnv:HOME}${localEnv:USERPROFILE}/.aws,target=/home/vscode/.aws,type=bind,consistency=cached",
	]

参考URL: https://code.visualstudio.com/docs/remote/containers-advanced#_adding-another-local-file-mount

XeresXeres

とりあえず実装はそのままに、一通りの形式をテスト。

# codecommit::region://profile@repository 形式
$ ghq get codecommit::us-east-1://main@MyDemoRepo
     clone codecommit::us-east-1://main@MyDemoRepo -> /home/vscode/ghq/us-east-1/MyDemoRepo
       git clone --recursive codecommit::us-east-1://main@MyDemoRepo /home/vscode/ghq/us-east-1/MyDemoRepo
Cloning into '/home/vscode/ghq/us-east-1/MyDemoRepo'...
warning: You appear to have cloned an empty repository.
Process exiting with code: 0

# codecommit::region://repository 形式
$ ghq get codecommit::us-east-1://MyDemoRepo
     clone  -> /home/vscode/ghq/us-east-1/MyDemoRepo
       git clone --recursive codecommit::us-east-1://MyDemoRepo /home/vscode/ghq/us-east-1/MyDemoRepo
Cloning into '/home/vscode/ghq/us-east-1/MyDemoRepo'...
warning: You appear to have cloned an empty repository.
Process exiting with code: 0

# codecommit://profile@repository 形式
$ ghq get codecommit://main@MyDemoRepo
     clone codecommit://main@MyDemoRepo -> /home/vscode/ghq/MyDemoRepo
       git clone --recursive codecommit://main@MyDemoRepo /home/vscode/ghq/MyDemoRepo
Cloning into '/home/vscode/ghq/MyDemoRepo'...
warning: You appear to have cloned an empty repository.
Process exiting with code: 0

# codecommit://repository 形式
$ ghq get codecommit://MyDemoRepo
     clone codecommit://MyDemoRepo -> /home/vscode/ghq/MyDemoRepo
       git clone --recursive codecommit://MyDemoRepo /home/vscode/ghq/MyDemoRepo
Cloning into '/home/vscode/ghq/MyDemoRepo'...
warning: You appear to have cloned an empty repository.
Process exiting with code: 0

一通り git clone 自体は動作するけど、ローカルリポジトリのパスがリージョンを指定している形式、していない仮想が分かれてしまうので、その点が難点。LocalRepository.relPathaws configure get region あたりで取ってきた値を付け加える処理が必要そう。

あと、LocalRepository.relPath が今は region/repository になっているが、ここに AWS CLI プロファイル名を含めて、region/profile/repository とするべきかどうかを悩んでいる。

github.com なんかは github.com/user/repository になっているので、こちらの方が正しいかも。

XeresXeres

仕様についての検討。

codecommit::region//profile@repository 形式を $GHQ_ROOT/region/profile/repository に格納するべきか、$GHQ_ROOT/region/repository に格納するべきか。

EC2 などで利用している場合、IAM インスタンスプロファイルを参照している可能性がある。CLI でも、$AWS_ACCESS_KEY_ID$AWS_ACCESS_SECRET_KEY (や $AWS_SESSION_TOKEN)を利用しているケースが考えられるので、必ずしもプロファイル名があるとは限らない。そのため、$GHQ_ROOT/region/repository に格納するべきと判断。

codecommit::region//profile-A@repositorycodecommit::region//profile-B@repository が必ずしも同じリポジトリを指すわけではないものの、ghq.root の設定は複数設定できるので、必要に応じて回避できるはず。

XeresXeres

とりあえず動くものは出来た。

改善したい点としては、

if url.Scheme == "codecommit" で Adhoc な対応しているところをリファクタリングしたいのと、AWSリージョンが明示的に指定されていない場合のリージョン判定を、今は単純に aws configure get region の結果を利用しているのだが、設定の基本 - AWS コマンドラインインターフェイス 》 構成設定と優先順位と揃えたい。

XeresXeres

リージョン判定のロジックを修正した上で PR した。
アドホックな判定が多いので見直したいと考えていたが、そこまで Go が書けるわけでもないし、結構手を入れないといけないので、シンプルにやりたいことが出来る、かつ既存のテストに影響を与えないことだけを確認して、PR してみることにした。reject されたら、GitHub と HTTP (GRC) だけサポートした類似アプリ作って自分で使えばよいと判断。
https://github.com/x-motemen/ghq/issues/320
https://github.com/x-motemen/ghq/pull/321

GitHub Actions でテスト用のワークフローが書かれていたので手元に fork したリポジトリでもテストできるのかと思ったが、よくやり方が分からず。まあ、ローカルで go test した感じは問題なさそうだし、そのまま PR してみた。

こっちも勉強しなきゃだなあ…。

自分がコードを書いた部分のテストが出来ていないので全体のテストカバレッジ率が落ちたものの、特に問題はなかった模様。

XeresXeres

https://twitter.com/3socha/status/1396379504524726274

む、不具合があるとの報告あり。

$ git --version
git version 2.25.1
$ ghq --version
ghq version 1.2.0 (rev:97c992f)
$ pipx list | grep git-remote-codecommit
   package git-remote-codecommit 1.15.1, Python 3.8.8
    - git-remote-codecommit
$ export | grep AWS
AWS_PROFILE=main
$ ghq get codecommit::ap-northeast-1://MyDemoRepo2
     clone codecommit::ap-northeast-1://MyDemoRepo2 -> /home/xeres/repos/ap-northeast-1/MyDemoRepo2
       git clone --recursive codecommit::ap-northeast-1://MyDemoRepo2 /home/xeres/repos/ap-northeast-1/MyDemoRepo2
Cloning into '/home/xeres/repos/ap-northeast-1/MyDemoRepo2'...
warning: You appear to have cloned an empty repository.

あれ、動くな…。

あ、僕は $GHQ_ROOT を使っていたので、もしかして ghq.root~/.gitconfig 側で設定してるとダメなのかな。

$ unset $GHQ_ROOT
$ echo "[ghq]\nroot = ~/repos" >> ~/.gitconfig
$ rm -rf ~/repos/ap-northeast-1/MyDemoRepo2
$ ghq get codecommit::ap-northeast-1://MyDemoRepo2
fatal: invalid URL scheme name or missing '://' suffix
     error failed to get "codecommit::ap-northeast-1://MyDemoRepo2": exit status 128

はい、再現したー!

XeresXeres

https://github.com/git/git/blob/master/urlmatch.c#L163

git が URL として : を含んだものをサポートしていないのが原因。

ghq 側が、環境変数 GHQ_ROOT が存在しない場合に git config --path --get-urlmatch ghq.root <URL> を呼んでいるので、ここでエラーを吐くっぽい。

修正方法としては下記のようなものが考えられる。

  1. git 側を修正 (無理ゲー)
  2. AWS にカチ込む (無理ゲー)
  3. HTTPS (GRC) 形式の URL が渡された場合にのみ、
    1. --get-regexp で引っかけて git 内でやっている urlmatch をシミュレート (修正が重い)
    2. ghq.<base>.root を見なかったことにする (簡単)

というわけで、3.2. を選択して hotfix を送ることにした。これなら、~/.gitconfig を使っている既存ユーザーは困らないはず。

その代わり、HTTPS (GRC) 形式を使う人は ghq.<base>.root に codecommit の URL を指定できないのが難点。根本的な解決は 3.1. になるはず。

https://twitter.com/xerespm/status/1396441010125742080

XeresXeres

僕がトラシュしているのを Songmu さんが見てくれていたのか、秒速でマージしてくれた。
大変ありがたい。

https://github.com/x-motemen/ghq/releases/tag/v1.2.1

フィードバックいただいた本人からも治ったと言われたので、スクラップは close することに。

このスクラップは2021/05/28にクローズされました