github.com/grafana/pyroscope@v1.18.0/tools/update-contributors/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "log" 8 "net/http" 9 "os" 10 "strings" 11 ) 12 13 type contributor struct { 14 Login string `json:"login"` 15 AvatarURL string `json:"avatar_url"` 16 HTMLURL string `json:"html_url"` 17 } 18 19 func fetchContributors(ctx context.Context, owner, repo string) ([]contributor, error) { 20 url := fmt.Sprintf("https://api.github.com/repos/%s/%s/contributors?per_page=200", owner, repo) 21 req, err := http.NewRequest("GET", url, nil) 22 if err != nil { 23 return nil, err 24 } 25 req = req.WithContext(ctx) 26 27 resp, err := http.DefaultClient.Do(req) 28 if err != nil { 29 return nil, err 30 } 31 defer resp.Body.Close() 32 33 if resp.StatusCode != http.StatusOK { 34 return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) 35 } 36 37 var contributors []contributor 38 if err := json.NewDecoder(resp.Body).Decode(&contributors); err != nil { 39 return nil, err 40 } 41 42 return contributors, nil 43 } 44 45 func generateContributors() (string, error) { 46 ctx := context.Background() 47 contributors, err := fetchContributors(ctx, "grafana", "pyroscope") 48 if err != nil { 49 return "", err 50 } 51 52 sb := strings.Builder{} 53 54 limit := 9 * 7 55 56 for _, c := range contributors { 57 // filter bots 58 if strings.HasSuffix(c.Login, "[bot]") || c.Login == "pyroscopebot" { 59 continue 60 } 61 sb.WriteString(`<a href="`) 62 sb.WriteString(c.HTMLURL) 63 sb.WriteString(`"><img src="`) 64 sb.WriteString(c.AvatarURL) 65 sb.WriteString(`" title="`) 66 sb.WriteString(c.Login) 67 sb.WriteString(`" width="80" height="80"></a>`) 68 sb.WriteByte('\n') 69 limit-- 70 if limit == 0 { 71 break 72 } 73 } 74 75 return sb.String(), nil 76 } 77 78 const ( 79 marker = "[//]: contributor-faces" 80 readmeFile = "README.md" 81 ) 82 83 func replaceReadme() error { 84 b, err := os.ReadFile(readmeFile) 85 if err != nil { 86 return err 87 } 88 s := string(b) 89 90 start := strings.Index(s, marker) 91 if start == -1 { 92 return fmt.Errorf("could not find marker %q", marker) 93 } 94 start += len(marker) + 1 95 96 end := strings.Index(s[start:], marker) 97 if end == -1 { 98 return fmt.Errorf("could not find end marker %q", marker) 99 } 100 end += start 101 102 contributor, err := generateContributors() 103 if err != nil { 104 return err 105 } 106 107 f, err := os.Create(readmeFile) 108 if err != nil { 109 return err 110 } 111 112 defer f.Close() 113 114 _, err = f.WriteString(s[:start]) 115 if err != nil { 116 return err 117 } 118 119 _, err = f.WriteString(contributor) 120 if err != nil { 121 return err 122 } 123 124 _, err = f.WriteString("\n") 125 if err != nil { 126 return err 127 } 128 129 _, err = f.WriteString(s[end:]) 130 if err != nil { 131 return err 132 } 133 134 return nil 135 } 136 137 func main() { 138 if err := replaceReadme(); err != nil { 139 log.Fatal(err) 140 } 141 }