1diff --git a/config.example.scfg b/config.example.scfg
2index 59a04ad1644103962c89fb9c498e64d1035b3666..3ba89594f3683497a1ab44cdff372ed1eb1dfebc 100644
3--- a/config.example.scfg
4+++ b/config.example.scfg
5@@ -10,6 +10,14 @@ # and login UI will be disabled, and only public repository will be displayed.
6 passphrase $2a$14$VnB/ZcB1DUDkMnosRA6Y7.dj8h5eroslDxTeXlLwfQX/x86mh6WAq
7 aes-key 8XHptZxSWCGs1m7QzztX5zNQ7D9NiQevVX0DaUTNMbDpRwFzoJiB0U7K6O/kqIt01jJVgzBUfiR8ES46ZLLb4w==
8
9+# order of the list of repository, values:
10+# unordered
11+# alphabetical-asc
12+# alphabetical-desc
13+# lastcommit-asc
14+# lastcommit-desc
15+order-by lastcommit-asc
16+
17 # repository section is order dependent where the first repository has priority
18 # in case of conflict. Repository has also priority over scan. The order
19 # between scan and repository is irrelevant which means that all repository
20diff --git a/pkg/config/config.go b/pkg/config/config.go
21index 1ad5108b7b9319683627faa0e89059686d9b0a10..60a34443248c65059a5aeed1b49e6055acab33fa 100644
22--- a/pkg/config/config.go
23+++ b/pkg/config/config.go
24@@ -4,6 +4,7 @@ import (
25 "errors"
26 "fmt"
27 "io"
28+ "log/slog"
29 "os"
30 "path"
31 "path/filepath"
32@@ -19,6 +20,16 @@ ErrRepoPath = errors.New("Repository path does not exist")
33 ErrInvalidProperty = errors.New("Invalid property")
34 )
35
36+type OrderBy int
37+
38+const (
39+ Unordered OrderBy = iota
40+ AlphabeticalAsc
41+ AlphabeticalDesc
42+ LastCommitAsc
43+ LastCommitDesc
44+)
45+
46 type (
47
48 // scan represents piece of the scan from the configuration file.
49@@ -36,6 +47,7 @@ ListenAddr string
50 Passphrase string
51 SyntaxHighlight string
52 AESKey string
53+ OrderBy string
54 Repositories []*GitRepositoryConfiguration
55 }
56
57@@ -58,6 +70,7 @@ listenAddr string
58 passphrase []byte
59 aesKey []byte
60 syntaxHighlight string
61+ orderBy OrderBy
62 repositories []*GitRepositoryConfiguration
63 }
64 )
65@@ -80,6 +93,7 @@ passphrase: []byte(config.Passphrase),
66 repositories: config.Repositories,
67 rootReadme: config.RootReadme,
68 syntaxHighlight: config.SyntaxHighlight,
69+ orderBy: parseOrderBy(config.OrderBy),
70 }
71
72 for _, scan := range config.Scans {
73@@ -97,6 +111,10 @@
74 // GetRootReadme returns root read path
75 func (c *ConfigurationRepository) GetRootReadme() string {
76 return c.rootReadme
77+}
78+
79+func (c *ConfigurationRepository) GetOrderBy() OrderBy {
80+ return c.orderBy
81 }
82
83 func (c *ConfigurationRepository) GetSyntaxHighlight() string {
84@@ -211,6 +229,11 @@ if err != nil {
85 return nil, err
86 }
87
88+ err = setOrderby(block, &config.OrderBy)
89+ if err != nil {
90+ return nil, err
91+ }
92+
93 err = setRepositories(block, &config.Repositories)
94 if err != nil {
95 return nil, err
96@@ -316,6 +339,11 @@ scanDir := block.Get("syntax-highlight")
97 return setString(scanDir, listenAddr)
98 }
99
100+func setOrderby(block scfg.Block, orderBy *string) error {
101+ scanDir := block.Get("order-by")
102+ return setString(scanDir, orderBy)
103+}
104+
105 func setListenAddr(block scfg.Block, listenAddr *string) error {
106 scanDir := block.Get("listen-addr")
107 return setString(scanDir, listenAddr)
108@@ -363,3 +391,24 @@ *field = u.FirstOrZero(dir.Params)
109 }
110 return nil
111 }
112+
113+func parseOrderBy(s string) OrderBy {
114+ switch s {
115+ case "":
116+ return LastCommitAsc
117+ case "unordered":
118+ return Unordered
119+ case "alphabetical-asc":
120+ return AlphabeticalAsc
121+ case "alphabetical-desc":
122+ return AlphabeticalDesc
123+ case "lastcommit-asc":
124+ return LastCommitAsc
125+ case "lastcommit-desc":
126+ return LastCommitDesc
127+ default:
128+ slog.Warn("Invalid order-by using default unordered")
129+ return LastCommitAsc
130+
131+ }
132+}
133diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
134index 436d36430c4c952af21c7fb95c9af8018cdd414f..9c7ba5b1ee25615a2347ae54a661ea06372a33c6 100644
135--- a/pkg/handler/git/handler.go
136+++ b/pkg/handler/git/handler.go
137@@ -9,8 +9,10 @@ "log/slog"
138 "net/http"
139 "os"
140 "path/filepath"
141+ "sort"
142 "strings"
143
144+ "git.gabrielgio.me/cerrado/pkg/config"
145 "git.gabrielgio.me/cerrado/pkg/ext"
146 "git.gabrielgio.me/cerrado/pkg/service"
147 "git.gabrielgio.me/cerrado/pkg/u"
148@@ -34,6 +36,7 @@
149 configurationRepository interface {
150 GetRootReadme() string
151 GetSyntaxHighlight() string
152+ GetOrderBy() config.OrderBy
153 }
154 )
155
156@@ -79,7 +82,7 @@
157 bs = markdown.Render(doc, renderer)
158
159 gitList := &templates.GitListPage{
160- Respositories: repos,
161+ Respositories: orderBy(repos, g.config.GetOrderBy()),
162 About: bs,
163 }
164 templates.WritePageTemplate(w, gitList, r.Context())
165@@ -390,3 +393,26 @@
166 func isPublic(r *service.Repository) bool {
167 return r.Public
168 }
169+
170+func orderBy(repos []*service.Repository, order config.OrderBy) []*service.Repository {
171+ switch order {
172+ case config.AlphabeticalAsc:
173+ sort.Slice(repos, func(i, j int) bool {
174+ return repos[i].Name < repos[j].Name
175+ })
176+ case config.AlphabeticalDesc:
177+ sort.Slice(repos, func(i, j int) bool {
178+ return repos[i].Name > repos[j].Name
179+ })
180+ case config.LastCommitAsc:
181+ sort.Slice(repos, func(i, j int) bool {
182+ return repos[i].LastCommit.Committer.When.Before(repos[j].LastCommit.Committer.When)
183+ })
184+ case config.LastCommitDesc:
185+ sort.Slice(repos, func(i, j int) bool {
186+ return repos[i].LastCommit.Committer.When.After(repos[j].LastCommit.Committer.When)
187+ })
188+ }
189+
190+ return repos
191+}