Repository: jesseduffield/lazygit (language: go)

Issue:
Add Gitea to PR list
I would love to add Gitea support to lazygit.

I've just merged https://github.com/go-gitea/gitea/pull/17908 which allows the default branch to be inferred for a PR (which I see the other forges currently in lazygit support)

The PR above will appear in Gitea v1.16.0, which should be released (at a hazy guess) within the next month or so.

Prior to that (or if anyone uses the PR link on an outdated version) users will get a 404, and I don't want you to have to deal with questions if they come here. 🙂 

That being said, how long would you like me to wait before sending a PR?



Discussion / hints:
Nice, I'm honestly fine with you sending a PR whenever. We could merge it behind a feature flag (i.e. `if false {`) and do a follow-up PR to remove the guard. What do you think?
I think that would be a good idea. I'll kick it around a bit more and then open a PR for review. 

Thanks for the feedback!
Could this include self-hosted gitea as well? Some kind of `gitea.domain.tld`

https://github.com/jesseduffield/lazygit/blob/990dc8c4ea1133a58d5c863abd543ee5cde1e700/pkg/commands/pull_request.go#L28-L43

Fix patch:
diff --git a/docs/Config.md b/docs/Config.md
index df9003d23b1..92cc9ebd72f 100644
--- a/docs/Config.md
+++ b/docs/Config.md
@@ -474,7 +474,7 @@ services:
 Where:
 
 - `gitDomain` stands for the domain used by git itself (i.e. the one present on clone URLs), e.g. `git.work.com`
-- `provider` is one of `github`, `bitbucket`, `bitbucketServer`, `azuredevops` or `gitlab`
+- `provider` is one of `github`, `bitbucket`, `bitbucketServer`, `azuredevops`, `gitlab` or `gitea`
 - `webDomain` is the URL where your git service exposes a web interface and APIs, e.g. `gitservice.work.com`
 
 ## Predefined commit message prefix
diff --git a/pkg/commands/hosting_service/definitions.go b/pkg/commands/hosting_service/definitions.go
index 8dab166aa52..bfe374640cd 100644
--- a/pkg/commands/hosting_service/definitions.go
+++ b/pkg/commands/hosting_service/definitions.go
@@ -64,12 +64,22 @@ var bitbucketServerServiceDef = ServiceDefinition{
 	repoURLTemplate: "https://{{.webDomain}}/projects/{{.project}}/repos/{{.repo}}",
 }
 
+var giteaServiceDef = ServiceDefinition{
+	provider:                        "gitea",
+	pullRequestURLIntoDefaultBranch: "/compare/{{.From}}",
+	pullRequestURLIntoTargetBranch:  "/compare/{{.To}}...{{.From}}",
+	commitURL:                       "/commit/{{.CommitSha}}",
+	regexStrings:                    defaultUrlRegexStrings,
+	repoURLTemplate:                 defaultRepoURLTemplate,
+}
+
 var serviceDefinitions = []ServiceDefinition{
 	githubServiceDef,
 	bitbucketServiceDef,
 	gitLabServiceDef,
 	azdoServiceDef,
 	bitbucketServerServiceDef,
+	giteaServiceDef,
 }
 
 var defaultServiceDomains = []ServiceDomain{
@@ -93,4 +103,9 @@ var defaultServiceDomains = []ServiceDomain{
 		gitDomain:         "dev.azure.com",
 		webDomain:         "dev.azure.com",
 	},
+	{
+		serviceDefinition: giteaServiceDef,
+		gitDomain:         "try.gitea.io",
+		webDomain:         "try.gitea.io",
+	},
 }
diff --git a/pkg/commands/hosting_service/hosting_service.go b/pkg/commands/hosting_service/hosting_service.go
index 091da3ebb20..dd06e1cb713 100644
--- a/pkg/commands/hosting_service/hosting_service.go
+++ b/pkg/commands/hosting_service/hosting_service.go
@@ -13,7 +13,7 @@ import (
 	"github.com/jesseduffield/generics/slices"
 )
 
-// This package is for handling logic specific to a git hosting service like github, gitlab, bitbucket, etc.
+// This package is for handling logic specific to a git hosting service like github, gitlab, bitbucket, gitea, etc.
 // Different git hosting services have different URL formats for when you want to open a PR or view a commit,
 // and this package's responsibility is to determine which service you're using based on the remote URL,
 // and then which URL you need for whatever use case you have.


Test patch:
diff --git a/pkg/commands/hosting_service/hosting_service_test.go b/pkg/commands/hosting_service/hosting_service_test.go
index a3b128b0161..4a58a397586 100644
--- a/pkg/commands/hosting_service/hosting_service_test.go
+++ b/pkg/commands/hosting_service/hosting_service_test.go
@@ -264,6 +264,60 @@ func TestGetPullRequestURL(t *testing.T) {
 				assert.Equal(t, "https://mycompany.bitbucket.com/projects/myproject/repos/myrepo/pull-requests?create&targetBranch=dev&sourceBranch=feature%2Fnew", url)
 			},
 		},
+		{
+			testName:  "Opens a link to new pull request on Gitea Server (SSH)",
+			from:      "feature/new",
+			remoteUrl: "ssh://git@mycompany.gitea.io/myproject/myrepo.git",
+			configServiceDomains: map[string]string{
+				// valid configuration for a gitea server URL
+				"mycompany.gitea.io": "gitea:mycompany.gitea.io",
+			},
+			test: func(url string, err error) {
+				assert.NoError(t, err)
+				assert.Equal(t, "https://mycompany.gitea.io/myproject/myrepo/compare/feature%2Fnew", url)
+			},
+		},
+		{
+			testName:  "Opens a link to new pull request on Gitea Server (SSH) with specific target",
+			from:      "feature/new",
+			to:        "dev",
+			remoteUrl: "ssh://git@mycompany.gitea.io/myproject/myrepo.git",
+			configServiceDomains: map[string]string{
+				// valid configuration for a gitea server URL
+				"mycompany.gitea.io": "gitea:mycompany.gitea.io",
+			},
+			test: func(url string, err error) {
+				assert.NoError(t, err)
+				assert.Equal(t, "https://mycompany.gitea.io/myproject/myrepo/compare/dev...feature%2Fnew", url)
+			},
+		},
+		{
+			testName:  "Opens a link to new pull request on Gitea Server (HTTP)",
+			from:      "feature/new",
+			remoteUrl: "https://mycompany.gitea.io/myproject/myrepo.git",
+			configServiceDomains: map[string]string{
+				// valid configuration for a gitea server URL
+				"mycompany.gitea.io": "gitea:mycompany.gitea.io",
+			},
+			test: func(url string, err error) {
+				assert.NoError(t, err)
+				assert.Equal(t, "https://mycompany.gitea.io/myproject/myrepo/compare/feature%2Fnew", url)
+			},
+		},
+		{
+			testName:  "Opens a link to new pull request on Gitea Server (HTTP) with specific target",
+			from:      "feature/new",
+			to:        "dev",
+			remoteUrl: "https://mycompany.gitea.io/myproject/myrepo.git",
+			configServiceDomains: map[string]string{
+				// valid configuration for a gitea server URL
+				"mycompany.gitea.io": "gitea:mycompany.gitea.io",
+			},
+			test: func(url string, err error) {
+				assert.NoError(t, err)
+				assert.Equal(t, "https://mycompany.gitea.io/myproject/myrepo/compare/dev...feature%2Fnew", url)
+			},
+		},
 		{
 			testName:  "Throws an error if git service is unsupported",
 			from:      "feature/divide-operation",
@@ -310,7 +364,7 @@ func TestGetPullRequestURL(t *testing.T) {
 				assert.NoError(t, err)
 				assert.Equal(t, "https://bitbucket.org/johndoe/social_network/pull-requests/new?source=feature%2Fprofile-page&t=1", url)
 			},
-			expectedLoggedErrors: []string{"Unknown git service type: 'noservice'. Expected one of github, bitbucket, gitlab, azuredevops, bitbucketServer"},
+			expectedLoggedErrors: []string{"Unknown git service type: 'noservice'. Expected one of github, bitbucket, gitlab, azuredevops, bitbucketServer, gitea"},
 		},
 		{
 			testName:  "Escapes reserved URL characters in from branch name",