diff --git a/.gitignore b/.gitignore index cd7fbc6..cc5ffe8 100644 --- a/.gitignore +++ b/.gitignore @@ -120,3 +120,7 @@ modules.xml test.md test.html +list.md +list.html +table.md +table.html diff --git a/Dockerfile.build b/Dockerfile.build index dbea45f..dcfddba 100644 --- a/Dockerfile.build +++ b/Dockerfile.build @@ -25,5 +25,6 @@ ENV IGNORE_REPOS "" ENV WITH_TOC "true" ENV WITH_LICENSE "true" ENV WITH_STARS "true" +ENV WITH_BACK_TO_TOP "false" ENTRYPOINT ["stargazer"] diff --git a/README.md b/README.md index 623b3d5..1d398a5 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Like an [![Awesome](https://awesome.re/badge.svg)](https://awesome.re) list, but personal. Automated with GitHub-Actions. See [rverst/stars](https://github.com/rverst/stars) for an example. You can use -that repositorie as a template, the README.md will get overwritte with your own +that repository as a template, the README.md will get overwritten with your own list if you run the stargazer-action (runs daily at 02:42). ## Usage @@ -35,7 +35,7 @@ jobs: # Generate the list - name: Create star list id: stargazer - uses: rverst/stargazer@v1.2.0 + uses: rverst/stargazer@v1 with: github-user: ${{ github.actor }} github-token: ${{ secrets.GITHUB_TOKEN }} @@ -69,6 +69,7 @@ jobs: | with-toc | bool | false | Print table of contents (default: true) | | with-license | bool | false | Print license of repositories (default: true) | | with-stars | bool | false | Print starcount of repositories (default: true) | +| with-back-to-top | bool | false | Generate 'back to top' links for each language (default: false) | ## Custom templates diff --git a/action.yml b/action.yml index 4b7bed5..35ddd54 100644 --- a/action.yml +++ b/action.yml @@ -36,6 +36,10 @@ inputs: description: 'Print starcount of repositories' required: false default: 'true' + with-back-to-top: + description: 'Add [back to top] link for each language ' + required: false + default: 'false' runs: using: 'docker' image: 'Dockerfile' @@ -48,4 +52,5 @@ runs: - ${{ inputs.with-toc }} - ${{ inputs.with-license }} - ${{ inputs.with-stars }} + - ${{ inputs.with-back-to-top }} diff --git a/entrypoint.sh b/entrypoint.sh index d7666e5..5ee0267 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -8,5 +8,6 @@ export IGNORE_REPOS=$5 export WITH_TOC=$6 export WITH_LICENSE=$7 export WITH_STARS=$8 +export WITH_BACK_TOP=$9 stargazer -o "/github/workspace/$FILENAME" diff --git a/github.go b/github.go index ce9f3d2..9307921 100644 --- a/github.go +++ b/github.go @@ -2,10 +2,11 @@ package main import ( "context" - "github.com/shurcooL/githubv4" - "golang.org/x/oauth2" "strings" "time" + + "github.com/shurcooL/githubv4" + "golang.org/x/oauth2" ) type Star struct { diff --git a/go.sum b/go.sum index 063a419..edcea0b 100644 --- a/go.sum +++ b/go.sum @@ -80,6 +80,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -274,6 +275,7 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc 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= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= diff --git a/list_template.md b/list_template.md index 68cfb21..9eea639 100644 --- a/list_template.md +++ b/list_template.md @@ -1,23 +1,31 @@ -{{- $l := .WithLicense -}} -{{- $s := .WithStars -}} +{{- $wl := .WithLicense -}} +{{- $ws := .WithStars -}} +{{- $wb := .WithBtt -}} +{{- $a := .Anchors -}} +{{- $s := .Stars -}} # awesome stars {{ .Credits.Text }}{{ .Credits.Link }} Total starred repositories: `{{ .Total }}` -{{ if .WithToc }} +{{- if .WithToc }} ## Contents - {{ range $key, $value := .Stars }} -* [{{ $key }}](#{{ anchor $key }}) ({{ len $value }}) - {{- end }} +{{ range $key := .Keys }} + - [{{ $key }}](#{{ with (index $a $key) }}{{ . }}{{ end }}) {{- end }} +{{- end }} + -{{ range $key, $value := .Stars }} +{{ range $key := .Keys }} ## {{ $key }} - {{ range $value }} -- [{{- .NameWithOwner -}}]({{- .Url -}}) - {{ .Description }} -{{- if $l }}{{ with .License}} \[*{{ . }}*\]{{ end }}{{ end -}} -{{- if $s }} (⭐️{{ .Stars }}){{ end -}} +{{ with (index $s $key) }}{{ range . }} + - [{{- .NameWithOwner -}}]({{- .Url -}}) - {{ .Description }} +{{- if $wl }}{{ with .License}} \[*{{ . }}*\]{{ end }}{{ end -}} +{{- if $ws }} (⭐️{{ .Stars }}){{ end -}} {{- if .Archived }} *Archived!*{{ end -}} - {{- end }} +{{- end }} +{{- end }} +{{- if $wb }} + +**[⬆ back to top](#contents)**{{ end }} {{ end }} diff --git a/main.go b/main.go index c731dd4..91ee42d 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,7 @@ const ( defaultWithToc = true defaultWithStars = true defaultWithLicense = true + defaultWithBtt = false envUser = "GITHUB_USER" envToken = "GITHUB_TOKEN" @@ -32,6 +33,7 @@ const ( envToc = "WITH_TOC" envStars = "WITH_STARS" envLicense = "WITH_LICENSE" + envBttLink = "WITH_BACK_TO_TOP" ) var ( @@ -49,7 +51,7 @@ func main() { flaggy.SetVersion(version) var user, token, output, format string - var test, wToc, wStars, wLicense bool + var test, wToc, wStars, wLicense, wBtt bool wToc, wStars, wLicense = true, true, true flaggy.String(&output, "o", "output-file", "the file to create (default:"+defaultOutput+" )") flaggy.String( @@ -65,6 +67,7 @@ func main() { flaggy.Bool(&wToc, "", "with-toc", "print table of contents") flaggy.Bool(&wStars, "", "with-stars", "print starcount of repositories") flaggy.Bool(&wLicense, "", "with-license", "print license of repositories") + flaggy.Bool(&wBtt, "", "with-back-to-top", "generate 'back to top' links for each language") flaggy.Parse() @@ -115,8 +118,14 @@ func main() { wLicense = b } } + if wBtt == defaultWithBtt { + v := getEnv(envBttLink, fmt.Sprintf("%t", defaultWithBtt)) + if b, err := strconv.ParseBool(v); err == nil { + wBtt = b + } + } - if token == "" { + if token == "" && !test { log.Fatal("github token is required") } @@ -142,7 +151,7 @@ func main() { stars[k] = v } - err = writeList(output, stars, total, wToc, wLicense, wStars) + err = writeList(output, stars, total, wToc, wLicense, wStars, wBtt) if err != nil { log.Fatal(err) } @@ -191,7 +200,11 @@ func testStars() (stars map[string][]Star, total int) { stars["markdown"][0] = s } - stars["markdown"] = append(stars["markdown"], Star{ + stars["C#"] = make([]Star, 0) + stars["C++"] = make([]Star, 0) + stars["C##"] = make([]Star, 0) + + stars["C#"] = append(stars["C#"], Star{ Url: "https://github.com/rverst/test", Name: "test", NameWithOwner: "rverst/test", @@ -200,7 +213,7 @@ func testStars() (stars map[string][]Star, total int) { Stars: 1, StarredAt: time.Now(), }) - stars["markdown"] = append(stars["markdown"], Star{ + stars["C++"] = append(stars["C++"], Star{ Url: "https://github.com/rverst/test_2", Name: "test_2", NameWithOwner: "rverst/test_2", @@ -210,7 +223,7 @@ func testStars() (stars map[string][]Star, total int) { StarredAt: time.Now(), }) - stars["markdown"] = append(stars["markdown"], Star{ + stars["C##"] = append(stars["C##"], Star{ Url: "https://github.com/rverst/test_3", Name: "test_3", NameWithOwner: "rverst/test_3", diff --git a/table_template.md b/table_template.md index a406c16..7e7e87d 100644 --- a/table_template.md +++ b/table_template.md @@ -1,22 +1,30 @@ -{{- $l := .WithLicense -}} -{{- $s := .WithStars -}} +{{- $wl := .WithLicense -}} +{{- $ws := .WithStars -}} +{{- $wb := .WithBtt -}} +{{- $a := .Anchors -}} +{{- $s := .Stars -}} # awesome stars {{ .Credits.Text }}{{ .Credits.Link }} Total starred repositories: `{{ .Total }}` -{{ if .WithToc }} +{{- if .WithToc }} ## Contents - {{ range $key, $value := .Stars }} -* [{{ $key }}](#{{ anchor $key }}) ({{ len $value }}) - {{- end }} +{{ range $key := .Keys }} + - [{{ $key }}](#{{ with (index $a $key) }}{{ . }}{{ end }}) +{{- end }} {{- end }} -{{ range $key, $value := .Stars }} + +{{ range $key := .Keys }} ## {{ $key }} - {{ range $value }} -| | {{ if $l }}| {{ end }}{{ if $s }}| {{ end }}| -|-----|-----{{ if $l }}|:---:{{ end }}{{ if $s }}|----:{{ end }}| -| [{{- .NameWithOwner -}}]({{- .Url -}}) | {{ .Description }} {{ if .Archived }}(*archived*){{ end }} {{ if $l }}| {{ with .License}}{{ . }}{{ else }}-{{ end }}{{ end }} {{ if $s }}| ⭐️{{ .Stars }}{{ end }} | +{{ with (index $s $key) }}{{ range . }} +| Name | Description {{ if $wl }} | License {{ end }}{{ if $ws }} | Stars {{ end }} | +| ----- | -----{{ if $wl }} | :---:{{ end }}{{ if $ws }} |----:{{ end }} | +| [{{- .NameWithOwner -}}]({{- .Url -}}) | {{ .Description }} {{ if .Archived }}(*archived*){{ end }} {{ if $wl }} | {{ with .License}}{{ . }}{{ else }}-{{ end }}{{ end }} {{ if $ws }}| ⭐️{{ .Stars }}{{ end }} | {{- end }} {{- end }} +{{- if $wb }} + +**[⬆ back to top](#contents)**{{ end }} +{{- end }} diff --git a/template.go b/template.go index 3b672f6..a349a2d 100644 --- a/template.go +++ b/template.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" "os" + "regexp" + "sort" "strings" "text/template" ) @@ -34,6 +36,9 @@ type T struct { WithToc bool WithLicense bool WithStars bool + WithBtt bool + Keys []string + Anchors map[string]string Stars map[string][]Star Credits C } @@ -63,13 +68,12 @@ func initTemplate(tType string) (err error) { } } - temp, err = template.New("readme"). - Funcs(template.FuncMap{"anchor": Anchor}).Parse(t) + temp, err = template.New("readme").Parse(t) return } -func writeList(path string, stars map[string][]Star, total int, withToc, withLicense, withStars bool) error { +func writeList(path string, stars map[string][]Star, total int, withToc, withLicense, withStars, withBtt bool) error { if temp == nil { return errors.New("template not initialized") } @@ -97,17 +101,56 @@ func writeList(path string, stars map[string][]Star, total int, withToc, withLic Link: "[stargazer](" + creditUrl + ")", } + keys := make([]string, 0) + for k := range stars { + keys = append(keys, k) + } + sort.Strings(keys) + return temp.Execute(f, T{ + Keys: keys, + Anchors: toc(keys), Stars: stars, Total: total, Credits: c, WithToc: withToc, WithLicense: withLicense, WithStars: withStars, + WithBtt: withBtt, }) } -// todo: check rules for markdown anchors... -func Anchor(s string) string { - return strings.Replace(strings.ToLower(s), " ", "-", -1) +// toc returns the anchors for the table of contents +func toc(keys []string) map[string]string { + rx := regexp.MustCompile(`[^\w\- ]`) // regexp to remove all punctuation + anchors := make(map[string]string, 0) + + for _, k := range keys { + x := strings.ToLower(strings.TrimSpace(k)) + x = rx.ReplaceAllString(x, "") + x = strings.ReplaceAll(x, " ", "-") + + c := 0 + for { + add := true + y := x + if c > 0 { + y += fmt.Sprintf("-%d", c) + } + for _, val := range anchors { + if val == y { + c++ + add = false + break + } + } + + if !add { + continue + } + anchors[k] = y + break + } + } + return anchors }