Skip Navigation

Is there a Git repository activity aggregator, like GitHub's user activity but platform independent?

I'm looking for something like GitHub's user activity indicator that gathers information from a list of git repositories regardless of where they are hosted (as long as they are public), that I can put on my webpage, kind of as a thing to show what I'm working on at the moment.

Is this a thing that already exists? I'd started writing one a while ago but instead of reviving that it would be great if there's something that already exists and I can just use :)

8 comments
  • @2xsaiko RSS/Atom feeds were developed for this use case. GitHub, GitLab, Codeberg (Forgejo), Sourcehut, even cgit and git's own gitweb serve feeds. For example here's my GitHub account: https://github.com/ollytom.atom
    my main OSS project: https://git.olowe.co/streaming/atom/

    Atom feeds are widely supported (it's how I found this post!) and there are many libraries/apps/plugins for aggregation. Robust old tech. And no need to limit feeds to Git activity if you don't want to :) Good luck!

    @technology

    • Oh nice, I wasn't aware there were RSS feeds for git repositories! Makes sense though. I'll look into this.

  • I asked chatgpt to write a go program for this, this looks roughly correct (I have used both libraries before) obviously this won't be enough for your particular use case. I imagine you can integrate an RSS feed to your site, however if you're using something like hugo perhaps output it as a csv.

    Super low effort but a good start I think:

     go
        
    package main
    
    import (
        "fmt"
        "log"
        "os"
        "strings"
        "time"
    
        git "github.com/go-git/go-git/v5"
        rss "github.com/jteeuwen/go-pkg-rss"
    )
    
    const (
        timeout = 5 // timeout in seconds for the RSS feed generation
    )
    
    // Repository represents a git repository with its URL
    type Repository struct {
        URL string
    }
    
    // Repositories is the list of git repositories
    var Repositories = []Repository{
        {URL: "https://github.com/owner/repo1"},
        {URL: "https://github.com/owner/repo2"},
        // Add more repositories here
    }
    
    // FetchLatestTag fetches the latest tag from a git repository
    func FetchLatestTag(repoURL string) (string, string, error) {
        // Clone the repository to a temporary directory
        dir, err := os.MkdirTemp("", "repo")
        if err != nil {
            return "", "", err
        }
        defer os.RemoveAll(dir)
    
        _, err = git.PlainClone(dir, true, &git.CloneOptions{
            URL:      repoURL,
            Progress: os.Stdout,
        })
        if err != nil {
            return "", "", err
        }
    
        repo, err := git.PlainOpen(dir)
        if err != nil {
            return "", "", err
        }
    
        tags, err := repo.Tags()
        if err != nil {
            return "", "", err
        }
    
        var latestTag string
        var latestCommitTime time.Time
    
        err = tags.ForEach(func(ref *plumbing.Reference) error {
            tag := ref.Name().Short()
            commit, err := repo.CommitObject(ref.Hash())
            if err != nil {
                return err
            }
            if commit.Committer.When.After(latestCommitTime) {
                latestCommitTime = commit.Committer.When
                latestTag = tag
            }
            return nil
        })
        if err != nil {
            return "", "", err
        }
    
        return latestTag, latestCommitTime.Format(time.RFC1123Z), nil
    }
    
    // GenerateRSS generates an RSS feed from the latest tags of the repositories
    func GenerateRSS() string {
        feed := rss.Feed{
            Title:       "Latest Tags from Git Repositories",
            Link:        &rss.Link{Href: "http://example.com/"},
            Description: "This feed provides the latest tags from a list of git repositories.",
            Created:     time.Now(),
        }
    
        for _, repo := range Repositories {
            tag, date, err := FetchLatestTag(repo.URL)
            if err != nil {
                log.Printf("Error fetching latest tag for repository %s: %v", repo.URL, err)
                continue
            }
            feed.Items = append(feed.Items, &rss.Item{
                Title:       fmt.Sprintf("Latest tag for %s: %s", repo.URL, tag),
                Link:        &rss.Link{Href: repo.URL},
                Description: fmt.Sprintf("The latest tag for repository %s is %s, created on %s.", repo.URL, tag, date),
                Created:     time.Now(),
            })
        }
    
        var rssFeed strings.Builder
        rssFeed.WriteString(xml.Header)
        if err := feed.Write(&rssFeed); err != nil {
            log.Fatalf("Error generating RSS feed: %v", err)
        }
    
        return rssFeed.String()
    }
    
    func main() {
        rssFeed := GenerateRSS()
        fmt.Println(rssFeed)
    }
    
      
8 comments