github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/githubtemplate/github_template.go (about) 1 package githubtemplate 2 3 import ( 4 "fmt" 5 "os" 6 "path" 7 "regexp" 8 "sort" 9 "strings" 10 11 "gopkg.in/yaml.v3" 12 ) 13 14 // FindNonLegacy returns the list of template file paths from the template folder (according to the "upgraded multiple template builder") 15 func FindNonLegacy(rootDir string, name string) []string { 16 results := []string{} 17 18 // https://help.github.com/en/github/building-a-strong-community/creating-a-pull-request-template-for-your-repository 19 candidateDirs := []string{ 20 path.Join(rootDir, ".github"), 21 rootDir, 22 path.Join(rootDir, "docs"), 23 } 24 25 mainLoop: 26 for _, dir := range candidateDirs { 27 files, err := os.ReadDir(dir) 28 if err != nil { 29 continue 30 } 31 32 // detect multiple templates in a subdirectory 33 for _, file := range files { 34 if strings.EqualFold(file.Name(), name) && file.IsDir() { 35 templates, err := os.ReadDir(path.Join(dir, file.Name())) 36 if err != nil { 37 break 38 } 39 for _, tf := range templates { 40 if strings.HasSuffix(tf.Name(), ".md") { 41 results = append(results, path.Join(dir, file.Name(), tf.Name())) 42 } 43 } 44 if len(results) > 0 { 45 break mainLoop 46 } 47 break 48 } 49 } 50 } 51 sort.Strings(results) 52 return results 53 } 54 55 // FindLegacy returns the file path of the default(legacy) template 56 func FindLegacy(rootDir string, name string) string { 57 namePattern := regexp.MustCompile(fmt.Sprintf(`(?i)^%s(\.|$)`, strings.ReplaceAll(name, "_", "[_-]"))) 58 59 // https://help.github.com/en/github/building-a-strong-community/creating-a-pull-request-template-for-your-repository 60 candidateDirs := []string{ 61 path.Join(rootDir, ".github"), 62 rootDir, 63 path.Join(rootDir, "docs"), 64 } 65 for _, dir := range candidateDirs { 66 files, err := os.ReadDir(dir) 67 if err != nil { 68 continue 69 } 70 71 // detect a single template file 72 for _, file := range files { 73 if namePattern.MatchString(file.Name()) && !file.IsDir() { 74 return path.Join(dir, file.Name()) 75 } 76 } 77 } 78 return "" 79 } 80 81 // ExtractName returns the name of the template from YAML front-matter 82 func ExtractName(filePath string) string { 83 contents, err := os.ReadFile(filePath) 84 frontmatterBoundaries := detectFrontmatter(contents) 85 if err == nil && frontmatterBoundaries[0] == 0 { 86 templateData := struct { 87 Name string 88 }{} 89 if err := yaml.Unmarshal(contents[0:frontmatterBoundaries[1]], &templateData); err == nil && templateData.Name != "" { 90 return templateData.Name 91 } 92 } 93 return path.Base(filePath) 94 } 95 96 // ExtractContents returns the template contents without the YAML front-matter 97 func ExtractContents(filePath string) []byte { 98 contents, err := os.ReadFile(filePath) 99 if err != nil { 100 return []byte{} 101 } 102 if frontmatterBoundaries := detectFrontmatter(contents); frontmatterBoundaries[0] == 0 { 103 return contents[frontmatterBoundaries[1]:] 104 } 105 return contents 106 } 107 108 var yamlPattern = regexp.MustCompile(`(?m)^---\r?\n(\s*\r?\n)?`) 109 110 func detectFrontmatter(c []byte) []int { 111 if matches := yamlPattern.FindAllIndex(c, 2); len(matches) > 1 { 112 return []int{matches[0][0], matches[1][1]} 113 } 114 return []int{-1, -1} 115 }