diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7f6c491..15af530 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,7 +5,7 @@ jobs: build: strategy: matrix: - go-version: [~1.17, ^1] + go-version: [~1.18, ^1] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} env: diff --git a/README.md b/README.md index 3015c06..f01b7da 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ command-line. It currently supports the GitHub, GitLab, and Gitea APIs. ### From source -Make sure you have a working Go environment (Go 1.17 or higher is required). +Make sure you have a working Go environment (Go 1.18 or higher is required). See the [install instructions](http://golang.org/doc/install.html). Compiling gitty is easy, simply run: diff --git a/branch.go b/branch.go index 9b4d03c..8d45726 100644 --- a/branch.go +++ b/branch.go @@ -9,6 +9,7 @@ import ( "github.com/charmbracelet/lipgloss" "github.com/muesli/gitty/vcs" "github.com/muesli/reflow/truncate" + "github.com/muesli/termenv" ) func printBranch(branch vcs.Branch, stat *trackStat, maxWidth int) { @@ -24,7 +25,11 @@ func printBranch(branch vcs.Branch, stat *trackStat, maxWidth int) { Foreground(lipgloss.Color(theme.colorDarkGray)).Width(70 - maxWidth) var s string - s += numberStyle.Render(branch.Name) + name := numberStyle.Render(branch.Name) + if useLinks { + name = termenv.Hyperlink(branch.URL, name) + } + s += name s += genericStyle.Render(" ") s += stat.Render() s += genericStyle.Render(" ") @@ -32,7 +37,11 @@ func printBranch(branch vcs.Branch, stat *trackStat, maxWidth int) { s += genericStyle.Render(" ") s += timeStyle.Render(ago(branch.LastCommit.CommittedAt)) s += genericStyle.Render(" ") - s += authorStyle.Render(branch.LastCommit.Author) + author := authorStyle.Render(branch.LastCommit.Author) + if useLinks { + author = termenv.Hyperlink(branch.LastCommit.AuthorURL, author) + } + s += author fmt.Println(s) } diff --git a/commit.go b/commit.go index 861da46..c73e786 100644 --- a/commit.go +++ b/commit.go @@ -7,6 +7,7 @@ import ( "github.com/dustin/go-humanize" "github.com/muesli/gitty/vcs" "github.com/muesli/reflow/truncate" + "github.com/muesli/termenv" ) func printCommit(commit vcs.Commit) { @@ -20,13 +21,21 @@ func printCommit(commit vcs.Commit) { Foreground(lipgloss.Color(theme.colorDarkGray)).Width(80 - 7) var s string - s += numberStyle.Render(commit.ID[:7]) + sha := numberStyle.Render(commit.ID[:7]) + if useLinks { + sha = termenv.Hyperlink(commit.URL, sha) + } + s += sha s += genericStyle.Render(" ") s += titleStyle.Render(truncate.StringWithTail(commit.MessageHeadline, 80-7, "…")) s += genericStyle.Render(" ") s += timeStyle.Render(ago(commit.CommittedAt)) s += genericStyle.Render(" ") - s += numberStyle.Render(commit.Author) + author := numberStyle.Render(commit.Author) + if useLinks { + author = termenv.Hyperlink(commit.AuthorURL, author) + } + s += author fmt.Println(s) } @@ -40,16 +49,18 @@ func printCommits(repo vcs.Repo) { Foreground(lipgloss.Color(theme.colorMagenta)) // headerDimStyle := lipgloss.NewStyle(). // Foreground(lipgloss.Color(dimColor)) - sinceTag := repo.LastRelease.TagName - if sinceTag == "" { - sinceTag = "creation" + sinceTag := "creation" + if repo.LastRelease.TagName != "" { + sinceTag = repo.LastRelease.TagName + if useLinks { + sinceTag = termenv.Hyperlink(repo.LastRelease.URL, sinceTag) + } } + sinceTag = headerStyle.Render(sinceTag) - fmt.Printf("\n🔥 %s %s\n", - headerStyle.Render(fmt.Sprintf("%s %s", - pluralize(len(commits), "commit since", "commits since"), - sinceTag)), - + fmt.Printf("\n🔥 %s %s %s\n", + headerStyle.Render(pluralize(len(commits), "commit since", "commits since")), + sinceTag, headerStyle.Render(fmt.Sprintf("(%s)", humanize.Time(repo.LastRelease.PublishedAt))), ) diff --git a/go.mod b/go.mod index a494aa6..5e72d6d 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/muesli/gitty -go 1.17 +go 1.18 require ( code.gitea.io/sdk/gitea v0.15.1 @@ -34,12 +34,12 @@ require ( github.com/imdario/mergo v0.3.13 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762 // indirect github.com/muesli/kmeans v0.3.1 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect - github.com/rivo/uniseg v0.2.0 // indirect + github.com/rivo/uniseg v0.4.4 // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/shurcooL/graphql v0.0.0-20200928012149-18c5c3165e3a // indirect github.com/skeema/knownhosts v1.1.0 // indirect @@ -47,7 +47,7 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/crypto v0.6.0 // indirect golang.org/x/net v0.9.0 // indirect - golang.org/x/sys v0.7.0 // indirect + golang.org/x/sys v0.9.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.29.1 // indirect diff --git a/go.sum b/go.sum index 1d88a2a..dd344c8 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,3 @@ -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= @@ -41,12 +40,10 @@ github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= @@ -77,8 +74,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -102,8 +99,9 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/githubv4 v0.0.0-20211117020012-5800b9de5b8b h1:SAQLigkf0rd6emglkR1lRKRB9coWjib5OxnHmV1ZiFs= @@ -116,15 +114,10 @@ github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXi github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA= github.com/xanzy/go-gitlab v0.83.0 h1:37p0MpTPNbsTMKX/JnmJtY8Ch1sFiJzVF342+RvZEGw= github.com/xanzy/go-gitlab v0.83.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw= @@ -148,7 +141,6 @@ golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+o golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -160,16 +152,13 @@ golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -184,22 +173,19 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= -golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -207,9 +193,7 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -217,7 +201,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -225,7 +208,6 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -240,5 +222,4 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/issue.go b/issue.go index 91770c3..6abec1d 100644 --- a/issue.go +++ b/issue.go @@ -7,6 +7,7 @@ import ( "github.com/charmbracelet/lipgloss" "github.com/muesli/gitty/vcs" "github.com/muesli/reflow/truncate" + "github.com/muesli/termenv" ) func printIssue(issue vcs.Issue, maxWidth int) { @@ -20,7 +21,11 @@ func printIssue(issue vcs.Issue, maxWidth int) { Foreground(lipgloss.Color(theme.colorDarkGray)).Width(80 - maxWidth) var s string - s += numberStyle.Render(strconv.Itoa(issue.ID)) + num := numberStyle.Render(strconv.Itoa(issue.ID)) + if useLinks { + num = termenv.Hyperlink(issue.URL, num) + } + s += num s += genericStyle.Render(" ") s += titleStyle.Render(truncate.StringWithTail(issue.Title, uint(80-maxWidth), "…")) s += genericStyle.Render(" ") diff --git a/main.go b/main.go index 43b77a0..1a8065e 100644 --- a/main.go +++ b/main.go @@ -34,6 +34,8 @@ var ( version = flag.Bool("version", false, "display version") theme Theme + + useLinks = os.Getenv("GITTY_LINKS") != "" ) func parseRepository() { diff --git a/pr.go b/pr.go index 4b916ae..7790c26 100644 --- a/pr.go +++ b/pr.go @@ -7,6 +7,7 @@ import ( "github.com/charmbracelet/lipgloss" "github.com/muesli/gitty/vcs" "github.com/muesli/reflow/truncate" + "github.com/muesli/termenv" ) func printPullRequest(pr vcs.PullRequest, maxWidth int) { @@ -20,7 +21,11 @@ func printPullRequest(pr vcs.PullRequest, maxWidth int) { Foreground(lipgloss.Color(theme.colorDarkGray)).Width(80 - maxWidth) var s string - s += numberStyle.Render(strconv.Itoa(pr.ID)) + num := numberStyle.Render(strconv.Itoa(pr.ID)) + if useLinks { + num = termenv.Hyperlink(pr.URL, num) + } + s += num s += genericStyle.Render(" ") s += titleStyle.Render(truncate.StringWithTail(pr.Title, uint(80-maxWidth), "…")) s += genericStyle.Render(" ") diff --git a/release.go b/release.go index b354de8..36951e9 100644 --- a/release.go +++ b/release.go @@ -7,6 +7,7 @@ import ( "github.com/charmbracelet/lipgloss" "github.com/dustin/go-humanize" "github.com/muesli/gitty/vcs" + "github.com/muesli/termenv" ) func repoRelease(repo vcs.Repo) { @@ -51,8 +52,16 @@ func repoRelease(repo vcs.Repo) { } var s string - s += repoStyle.Render(repo.Name) - s += versionStyle.Render(" " + repo.LastRelease.TagName) + name := repoStyle.Render(repo.Name) + if useLinks { + name = termenv.Hyperlink(repo.URL, name) + } + s += name + " " + release := versionStyle.Render(repo.LastRelease.TagName) + if useLinks { + release = termenv.Hyperlink(repo.LastRelease.URL, release) + } + s += release s += genericStyle.Render(" (") s += dateStyle.Render(humanize.Time(repo.LastRelease.PublishedAt)) s += genericStyle.Render(", ") diff --git a/vcs/branch.go b/vcs/branch.go index a7e2d0e..9016f8f 100644 --- a/vcs/branch.go +++ b/vcs/branch.go @@ -4,4 +4,5 @@ package vcs type Branch struct { Name string LastCommit Commit + URL string } diff --git a/vcs/commit.go b/vcs/commit.go index 39451d4..1081cfd 100644 --- a/vcs/commit.go +++ b/vcs/commit.go @@ -10,4 +10,6 @@ type Commit struct { MessageHeadline string CommittedAt time.Time Author string + URL string + AuthorURL string } diff --git a/vcs/gitea/gitea.go b/vcs/gitea/gitea.go index 59cf74c..d380e9f 100644 --- a/vcs/gitea/gitea.go +++ b/vcs/gitea/gitea.go @@ -38,7 +38,7 @@ func NewClient(baseURL, token string, preverified bool) (*Client, error) { return &Client{ api: client, - host: baseURL, + host: u.String(), }, nil } @@ -74,6 +74,7 @@ func (c *Client) Issues(owner string, name string) ([]vcs.Issue, error) { ID: int(v.ID), Title: v.Title, CreatedAt: v.Created, + URL: v.HTMLURL, } for _, l := range v.Labels { issue.Labels = append(issue.Labels, vcs.Label{ @@ -115,6 +116,7 @@ func (c *Client) PullRequests(owner string, name string) ([]vcs.PullRequest, err ID: int(v.ID), Title: v.Title, CreatedAt: *v.Created, + URL: v.HTMLURL, } for _, l := range v.Labels { pr.Labels = append(pr.Labels, vcs.Label{ @@ -222,7 +224,10 @@ func (c *Client) Branches(owner string, name string) ([]vcs.Branch, error) { MessageHeadline: trimMessage(v.Commit.Message), CommittedAt: v.Commit.Timestamp, Author: v.Commit.Author.UserName, + URL: v.Commit.URL, + AuthorURL: fmt.Sprintf("%s/%s", c.host, v.Commit.Author.UserName), }, + URL: fmt.Sprintf("%s/%s/%s/src/branch/%s", c.host, owner, name, v.Name), } i = append(i, branch) } @@ -259,6 +264,8 @@ func (c *Client) History(repo vcs.Repo, max int, since time.Time) ([]vcs.Commit, MessageHeadline: trimMessage(v.RepoCommit.Message), CommittedAt: v.Created, Author: v.Author.UserName, + URL: v.HTMLURL, + AuthorURL: fmt.Sprintf("%s/%s", c.host, v.Author.UserName), }) } if brk { @@ -300,6 +307,7 @@ func (c *Client) repoFromAPI(p *gitea.Repository) vcs.Repo { Name: r[0].Title, TagName: r[0].TagName, PublishedAt: r[0].CreatedAt, + URL: r[0].HTMLURL, } } diff --git a/vcs/github/branch.go b/vcs/github/branch.go index 5b3119b..895871a 100644 --- a/vcs/github/branch.go +++ b/vcs/github/branch.go @@ -2,6 +2,7 @@ package github import ( "context" + "fmt" "github.com/muesli/gitty/vcs" "github.com/shurcooL/githubv4" @@ -36,6 +37,7 @@ func (c *Client) Branches(owner string, name string) ([]vcs.Branch, error) { branches = append(branches, vcs.Branch{ Name: string(node.Name), LastCommit: commitFromQL(node.Target.Commit), + URL: fmt.Sprintf("https://github.com/%s/%s/tree/%s", owner, name, string(node.Name)), }) } diff --git a/vcs/github/commit.go b/vcs/github/commit.go index df8d83b..649961a 100644 --- a/vcs/github/commit.go +++ b/vcs/github/commit.go @@ -34,8 +34,10 @@ type qlCommit struct { Author struct { User struct { Login githubv4.String + URL githubv4.String } } + URL githubv4.String } // History returns a list of commits for the given repository. @@ -70,5 +72,7 @@ func commitFromQL(commit qlCommit) vcs.Commit { MessageHeadline: string(commit.MessageHeadline), CommittedAt: commit.CommittedDate.Time, Author: string(commit.Author.User.Login), + URL: string(commit.URL), + AuthorURL: string(commit.Author.User.URL), } } diff --git a/vcs/github/issue.go b/vcs/github/issue.go index 4957b8d..c2540c8 100644 --- a/vcs/github/issue.go +++ b/vcs/github/issue.go @@ -35,6 +35,7 @@ type qlIssue struct { } } } `graphql:"labels(first: 100, orderBy: {field: NAME, direction: ASC})"` + URL githubv4.String } // Issues returns a list of issues for the given repository. @@ -71,6 +72,7 @@ func issueFromQL(issue qlIssue) vcs.Issue { Body: string(issue.Body), Title: string(issue.Title), CreatedAt: issue.CreatedAt.Time, + URL: string(issue.URL), } for _, v := range issue.Labels.Edges { diff --git a/vcs/github/pr.go b/vcs/github/pr.go index ceabd6a..1a158f4 100644 --- a/vcs/github/pr.go +++ b/vcs/github/pr.go @@ -35,6 +35,7 @@ type qlPullRequest struct { } } } `graphql:"labels(first: 100, orderBy: {field: NAME, direction: ASC})"` + URL githubv4.String } // PullRequests returns a list of pull requests for the given repository. @@ -71,6 +72,7 @@ func pullRequestFromQL(pr qlPullRequest) vcs.PullRequest { Body: string(pr.Body), Title: string(pr.Title), CreatedAt: pr.CreatedAt.Time, + URL: string(pr.URL), } for _, v := range pr.Labels.Edges { diff --git a/vcs/gitlab/gitlab.go b/vcs/gitlab/gitlab.go index 005b220..b13043b 100644 --- a/vcs/gitlab/gitlab.go +++ b/vcs/gitlab/gitlab.go @@ -26,8 +26,9 @@ func NewClient(baseURL, token string, preverified bool) (*Client, error) { if err != nil { return nil, fmt.Errorf("can't parse URL: %v", err) } - u.Path = path.Join(u.Path, "/api/v4") u.Scheme = "https" + host := u.String() + u.Path = path.Join(u.Path, "/api/v4") client, err := gitlab.NewClient(token, gitlab.WithBaseURL(u.String())) if err != nil { @@ -43,7 +44,7 @@ func NewClient(baseURL, token string, preverified bool) (*Client, error) { return &Client{ api: client, - host: baseURL, + host: host, colors: map[string]int{}, labelColors: map[string]string{}, }, nil @@ -82,6 +83,7 @@ func (c *Client) Issues(owner string, name string) ([]vcs.Issue, error) { ID: v.IID, Title: v.Title, CreatedAt: *v.CreatedAt, + URL: v.WebURL, } for _, l := range v.Labels { issue.Labels = append(issue.Labels, vcs.Label{ @@ -124,6 +126,7 @@ func (c *Client) PullRequests(owner string, name string) ([]vcs.PullRequest, err ID: v.IID, Title: v.Title, CreatedAt: *v.CreatedAt, + URL: v.WebURL, } for _, l := range v.Labels { pr.Labels = append(pr.Labels, vcs.Label{ @@ -232,6 +235,7 @@ func (c *Client) Branches(owner string, name string) ([]vcs.Branch, error) { CommittedAt: *v.Commit.CommittedDate, Author: v.Commit.CommitterName, }, + URL: v.WebURL, } i = append(i, branch) } @@ -266,6 +270,7 @@ func (c *Client) History(repo vcs.Repo, max int, since time.Time) ([]vcs.Commit, MessageHeadline: strings.ReplaceAll(v.Title, "\u00A0", " "), CommittedAt: *v.CommittedDate, Author: v.AuthorName, + URL: v.WebURL, }) } @@ -304,6 +309,7 @@ func (c *Client) repoFromAPI(p *gitlab.Project) vcs.Repo { Name: r[0].Name, TagName: r[0].TagName, PublishedAt: *r[0].CreatedAt, + URL: fmt.Sprintf("%s%s", c.host, r[0].TagPath), } } diff --git a/vcs/issue.go b/vcs/issue.go index df1f022..1a0b23a 100644 --- a/vcs/issue.go +++ b/vcs/issue.go @@ -11,4 +11,5 @@ type Issue struct { Title string Labels Labels CreatedAt time.Time + URL string } diff --git a/vcs/pr.go b/vcs/pr.go index b721323..e3bd710 100644 --- a/vcs/pr.go +++ b/vcs/pr.go @@ -11,4 +11,5 @@ type PullRequest struct { Title string Labels Labels CreatedAt time.Time + URL string }