88 "context"
99 "fmt"
1010 "html"
11+ "io"
1112 "net/http"
1213 "net/url"
1314 "path"
@@ -33,6 +34,7 @@ import (
3334 asymkey_service "code.gitea.io/gitea/services/asymkey"
3435
3536 "github.com/editorconfig/editorconfig-core-go/v2"
37+ "gopkg.in/yaml.v3"
3638)
3739
3840// IssueTemplateDirCandidates issue templates directory
@@ -47,6 +49,13 @@ var IssueTemplateDirCandidates = []string{
4749 ".gitlab/issue_template" ,
4850}
4951
52+ var IssueConfigCandidates = []string {
53+ ".gitea/ISSUE_TEMPLATE/config" ,
54+ ".gitea/issue_template/config" ,
55+ ".github/ISSUE_TEMPLATE/config" ,
56+ ".github/issue_template/config" ,
57+ }
58+
5059// PullRequest contains information to make a pull request
5160type PullRequest struct {
5261 BaseRepo * repo_model.Repository
@@ -1088,3 +1097,108 @@ func (ctx *Context) IssueTemplatesErrorsFromDefaultBranch() ([]*api.IssueTemplat
10881097 }
10891098 return issueTemplates , invalidFiles
10901099}
1100+
1101+ func GetDefaultIssueConfig () api.IssueConfig {
1102+ return api.IssueConfig {
1103+ BlankIssuesEnabled : true ,
1104+ ContactLinks : make ([]api.IssueConfigContactLink , 0 ),
1105+ }
1106+ }
1107+
1108+ // GetIssueConfig loads the given issue config file.
1109+ // It never returns a nil config.
1110+ func (r * Repository ) GetIssueConfig (path string , commit * git.Commit ) (api.IssueConfig , error ) {
1111+ if r .GitRepo == nil {
1112+ return GetDefaultIssueConfig (), nil
1113+ }
1114+
1115+ var err error
1116+
1117+ treeEntry , err := commit .GetTreeEntryByPath (path )
1118+ if err != nil {
1119+ return GetDefaultIssueConfig (), err
1120+ }
1121+
1122+ reader , err := treeEntry .Blob ().DataAsync ()
1123+ if err != nil {
1124+ log .Debug ("DataAsync: %v" , err )
1125+ return GetDefaultIssueConfig (), nil
1126+ }
1127+
1128+ defer reader .Close ()
1129+
1130+ configContent , err := io .ReadAll (reader )
1131+ if err != nil {
1132+ return GetDefaultIssueConfig (), err
1133+ }
1134+
1135+ issueConfig := api.IssueConfig {}
1136+ if err := yaml .Unmarshal (configContent , & issueConfig ); err != nil {
1137+ return GetDefaultIssueConfig (), err
1138+ }
1139+
1140+ for pos , link := range issueConfig .ContactLinks {
1141+ if link .Name == "" {
1142+ return GetDefaultIssueConfig (), fmt .Errorf ("contact_link at position %d is missing name key" , pos + 1 )
1143+ }
1144+
1145+ if link .URL == "" {
1146+ return GetDefaultIssueConfig (), fmt .Errorf ("contact_link at position %d is missing url key" , pos + 1 )
1147+ }
1148+
1149+ if link .About == "" {
1150+ return GetDefaultIssueConfig (), fmt .Errorf ("contact_link at position %d is missing about key" , pos + 1 )
1151+ }
1152+
1153+ _ , err = url .ParseRequestURI (link .URL )
1154+ if err != nil {
1155+ return GetDefaultIssueConfig (), fmt .Errorf ("%s is not a valid URL" , link .URL )
1156+ }
1157+ }
1158+
1159+ return issueConfig , nil
1160+ }
1161+
1162+ // IssueConfigFromDefaultBranch returns the issue config for this repo.
1163+ // It never returns a nil config.
1164+ func (ctx * Context ) IssueConfigFromDefaultBranch () (api.IssueConfig , error ) {
1165+ if ctx .Repo .Repository .IsEmpty {
1166+ return GetDefaultIssueConfig (), nil
1167+ }
1168+
1169+ commit , err := ctx .Repo .GitRepo .GetBranchCommit (ctx .Repo .Repository .DefaultBranch )
1170+ if err != nil {
1171+ return GetDefaultIssueConfig (), err
1172+ }
1173+
1174+ for _ , configName := range IssueConfigCandidates {
1175+ if _ , err := commit .GetTreeEntryByPath (configName + ".yaml" ); err == nil {
1176+ return ctx .Repo .GetIssueConfig (configName + ".yaml" , commit )
1177+ }
1178+
1179+ if _ , err := commit .GetTreeEntryByPath (configName + ".yml" ); err == nil {
1180+ return ctx .Repo .GetIssueConfig (configName + ".yml" , commit )
1181+ }
1182+ }
1183+
1184+ return GetDefaultIssueConfig (), nil
1185+ }
1186+
1187+ // IsIssueConfig returns if the given path is a issue config file.
1188+ func (r * Repository ) IsIssueConfig (path string ) bool {
1189+ for _ , configName := range IssueConfigCandidates {
1190+ if path == configName + ".yaml" || path == configName + ".yml" {
1191+ return true
1192+ }
1193+ }
1194+ return false
1195+ }
1196+
1197+ func (ctx * Context ) HasIssueTemplatesOrContactLinks () bool {
1198+ if len (ctx .IssueTemplatesFromDefaultBranch ()) > 0 {
1199+ return true
1200+ }
1201+
1202+ issueConfig , _ := ctx .IssueConfigFromDefaultBranch ()
1203+ return len (issueConfig .ContactLinks ) > 0
1204+ }
0 commit comments