rss email digests over ssh because you're a cool kid herald.dunkirk.sh
go rss rss-reader ssh charm

feat: add author and commit hash footer

dunkirk.sh dfd5418d cfca0d55

verified
+72 -26
+3 -1
README.md
··· 10 10 11 11 ```bash 12 12 # Build 13 - go build -o herald . 13 + go build -ldflags "-X main.commitHash=$(git log -1 --format=%H)" -o herald . 14 14 15 15 # Run the server 16 16 ./herald serve ··· 18 18 # Or with a config file 19 19 ./herald serve -c config.yaml 20 20 ``` 21 + 22 + > **Note:** The commit hash is automatically detected at runtime if not embedded at build time. 21 23 22 24 ## Usage 23 25
+22 -4
main.go
··· 4 4 "context" 5 5 "fmt" 6 6 "os" 7 + "os/exec" 8 + "strings" 7 9 "time" 8 10 9 11 "github.com/charmbracelet/fang" ··· 19 21 ) 20 22 21 23 var ( 22 - version = "dev" 23 - cfgFile string 24 - logger *log.Logger 24 + version = "dev" 25 + commitHash = "dev" 26 + cfgFile string 27 + logger *log.Logger 25 28 ) 26 29 27 30 func main() { ··· 121 124 } 122 125 } 123 126 127 + func getCommitHash() string { 128 + // Prefer build-time embedded hash 129 + if commitHash != "" && commitHash != "dev" { 130 + return commitHash 131 + } 132 + 133 + // Fallback to runtime git query 134 + cmd := exec.Command("git", "log", "-1", "--format=%H") 135 + output, err := cmd.Output() 136 + if err != nil { 137 + return "dev" 138 + } 139 + return strings.TrimSpace(string(output)) 140 + } 141 + 124 142 func runServer(ctx context.Context) error { 125 143 cfg, err := config.LoadAppConfig(cfgFile) 126 144 if err != nil { ··· 161 179 AllowedKeys: cfg.AllowedKeys, 162 180 }, db, sched, logger) 163 181 164 - webServer := web.NewServer(db, fmt.Sprintf("%s:%d", cfg.Host, cfg.HTTPPort), cfg.Origin, cfg.ExternalSSHPort, logger) 182 + webServer := web.NewServer(db, fmt.Sprintf("%s:%d", cfg.Host, cfg.HTTPPort), cfg.Origin, cfg.ExternalSSHPort, logger, getCommitHash()) 165 183 166 184 g, ctx := errgroup.WithContext(ctx) 167 185
+19 -8
web/handlers.go
··· 14 14 15 15 func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) { 16 16 host := parseOriginHost(s.origin) 17 + 18 + // Get short commit hash (first 7 chars) 19 + shortHash := s.commitHash 20 + if len(shortHash) > 7 { 21 + shortHash = shortHash[:7] 22 + } 23 + 17 24 data := struct { 18 - Origin string 19 - OriginHost string 20 - SSHHost string 21 - SSHPort int 25 + Origin string 26 + OriginHost string 27 + SSHHost string 28 + SSHPort int 29 + CommitHash string 30 + ShortCommitHash string 22 31 }{ 23 - Origin: s.origin, 24 - OriginHost: stripProtocol(s.origin), 25 - SSHHost: host, 26 - SSHPort: s.sshPort, 32 + Origin: s.origin, 33 + OriginHost: stripProtocol(s.origin), 34 + SSHHost: host, 35 + SSHPort: s.sshPort, 36 + CommitHash: s.commitHash, 37 + ShortCommitHash: shortHash, 27 38 } 28 39 if err := s.tmpl.ExecuteTemplate(w, "index.html", data); err != nil { 29 40 s.logger.Error("render index", "err", err)
+15 -13
web/server.go
··· 15 15 var templatesFS embed.FS 16 16 17 17 type Server struct { 18 - store *store.DB 19 - addr string 20 - origin string 21 - sshPort int 22 - logger *log.Logger 23 - tmpl *template.Template 18 + store *store.DB 19 + addr string 20 + origin string 21 + sshPort int 22 + logger *log.Logger 23 + tmpl *template.Template 24 + commitHash string 24 25 } 25 26 26 - func NewServer(st *store.DB, addr string, origin string, sshPort int, logger *log.Logger) *Server { 27 + func NewServer(st *store.DB, addr string, origin string, sshPort int, logger *log.Logger, commitHash string) *Server { 27 28 tmpl := template.Must(template.ParseFS(templatesFS, "templates/*.html")) 28 29 return &Server{ 29 - store: st, 30 - addr: addr, 31 - origin: origin, 32 - sshPort: sshPort, 33 - logger: logger, 34 - tmpl: tmpl, 30 + store: st, 31 + addr: addr, 32 + origin: origin, 33 + sshPort: sshPort, 34 + logger: logger, 35 + tmpl: tmpl, 36 + commitHash: commitHash, 35 37 } 36 38 } 37 39
+4
web/templates/index.html
··· 45 45 # Manual run 46 46 ssh {{if ne .SSHPort 22}}-p {{.SSHPort}} {{end}}herald@{{.SSHHost}} run feeds.txt 47 47 </pre> 48 + <footer> 49 + <span>Kieran Klukas &lt;https://dunkirk.sh&gt;</span> 50 + <span><a href="https://tangled.org/dunkirk.sh/herald/commit/{{.CommitHash}}">{{.ShortCommitHash}}</a></span> 51 + </footer> 48 52 </body> 49 53 </html>
+9
web/templates/style.css
··· 55 55 text-decoration: line-through; 56 56 opacity: 0.6; 57 57 } 58 + footer { 59 + display: flex; 60 + justify-content: space-between; 61 + margin-top: 2rem; 62 + padding-top: 1rem; 63 + border-top: 1px solid #333; 64 + font-size: 0.9rem; 65 + opacity: 0.8; 66 + }