commit dd2990ee488d38e5747b9c42bd90f2254385cf4b
parent 7eaa765f0b4887eeaf5574ad2b0ee62ff9d150e5
Author: Arjoonn Sharma <arjoonn@midpathsoftware.com>
Date: Sat, 28 Feb 2026 13:33:19 +0530
x
Diffstat:
2 files changed, 147 insertions(+), 12 deletions(-)
diff --git a/internal/jci/web.go b/internal/jci/web.go
@@ -12,9 +12,8 @@ import (
// BranchInfo holds branch data for the UI
type BranchInfo struct {
- Name string `json:"name"`
- IsRemote bool `json:"isRemote"`
- Commits []CommitInfo `json:"commits"`
+ Name string `json:"name"`
+ IsRemote bool `json:"isRemote"`
}
// CommitInfo holds commit data for the UI
@@ -60,12 +59,18 @@ func Web(args []string) error {
func handleRequest(w http.ResponseWriter, r *http.Request, repoRoot string) {
path := r.URL.Path
- // API endpoint for branch data
+ // API endpoint for branch data (names only, no commits)
if path == "/api/branches" {
serveBranchesAPI(w)
return
}
+ // API endpoint for paginated commits for a branch
+ if path == "/api/commits" {
+ serveCommitsAPI(w, r)
+ return
+ }
+
// API endpoint for commit info
if strings.HasPrefix(path, "/api/commit/") {
commit := strings.TrimPrefix(path, "/api/commit/")
@@ -332,7 +337,7 @@ func serveCommitAPI(w http.ResponseWriter, commit string) {
json.NewEncoder(w).Encode(detail)
}
-// serveBranchesAPI returns branch/commit data as JSON
+// serveBranchesAPI returns branch names as JSON (no commits for fast load)
func serveBranchesAPI(w http.ResponseWriter) {
branches, err := getLocalBranches()
if err != nil {
@@ -342,14 +347,9 @@ func serveBranchesAPI(w http.ResponseWriter) {
var branchInfos []BranchInfo
for _, branch := range branches {
- commits, err := getBranchCommits(branch, 20)
- if err != nil {
- continue
- }
branchInfos = append(branchInfos, BranchInfo{
Name: branch,
IsRemote: false,
- Commits: commits,
})
}
@@ -357,6 +357,141 @@ func serveBranchesAPI(w http.ResponseWriter) {
json.NewEncoder(w).Encode(branchInfos)
}
+// CommitsPage holds a page of commits for the paginated API
+type CommitsPage struct {
+ Branch string `json:"branch"`
+ Page int `json:"page"`
+ PageSize int `json:"pageSize"`
+ HasMore bool `json:"hasMore"`
+ Commits []CommitInfo `json:"commits"`
+}
+
+const commitsPageSize = 100
+
+// serveCommitsAPI returns a paginated list of commits for a branch.
+// Query params: branch (required), page (optional, 0-indexed, default 0)
+func serveCommitsAPI(w http.ResponseWriter, r *http.Request) {
+ branch := r.URL.Query().Get("branch")
+ if branch == "" {
+ http.Error(w, "branch query parameter is required", 400)
+ return
+ }
+
+ page := 0
+ if p := r.URL.Query().Get("page"); p != "" {
+ fmt.Sscanf(p, "%d", &page)
+ if page < 0 {
+ page = 0
+ }
+ }
+
+ // Fetch one extra commit beyond the page size to detect whether more pages exist
+ offset := page * commitsPageSize
+ limit := commitsPageSize + 1
+
+ commits, err := getBranchCommitsPaginated(branch, offset, limit)
+ if err != nil {
+ http.Error(w, err.Error(), 500)
+ return
+ }
+
+ hasMore := len(commits) > commitsPageSize
+ if hasMore {
+ commits = commits[:commitsPageSize]
+ }
+
+ result := CommitsPage{
+ Branch: branch,
+ Page: page,
+ PageSize: commitsPageSize,
+ HasMore: hasMore,
+ Commits: commits,
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(result)
+}
+
+// getBranchCommitsPaginated returns commits for a branch starting at the given offset.
+func getBranchCommitsPaginated(branch string, offset, limit int) ([]CommitInfo, error) {
+ out, err := git("log", branch,
+ fmt.Sprintf("--skip=%d", offset),
+ fmt.Sprintf("--max-count=%d", limit),
+ "--format=%H|%s")
+ if err != nil {
+ return nil, err
+ }
+ if out == "" {
+ return nil, nil
+ }
+
+ // Get local JCI refs (single-run)
+ jciRefs, _ := ListJCIRefs()
+ jciSet := make(map[string]bool)
+ for _, ref := range jciRefs {
+ commit := strings.TrimPrefix(ref, "jci/")
+ jciSet[commit] = true
+ }
+
+ // Get local JCI run refs (multi-run): commit -> list of run refs
+ jciRuns := make(map[string][]string)
+ runRefs, _ := ListJCIRunRefs()
+ for _, ref := range runRefs {
+ parts := strings.Split(strings.TrimPrefix(ref, "refs/jci-runs/"), "/")
+ if len(parts) >= 2 {
+ commit := parts[0]
+ jciRuns[commit] = append(jciRuns[commit], ref)
+ }
+ }
+
+ // Get remote JCI refs for CI push status
+ remoteCI := getRemoteJCIRefs("origin")
+
+ var commits []CommitInfo
+ for _, line := range strings.Split(out, "\n") {
+ parts := strings.SplitN(line, "|", 2)
+ if len(parts) != 2 {
+ continue
+ }
+ hash := parts[0]
+ msg := parts[1]
+
+ hasCI := jciSet[hash] || len(jciRuns[hash]) > 0
+ commit := CommitInfo{
+ Hash: hash,
+ ShortHash: hash[:7],
+ Message: msg,
+ HasCI: hasCI,
+ CIPushed: remoteCI["refs/jci/"+hash],
+ }
+
+ if jciSet[hash] {
+ commit.CIStatus = getCIStatus(hash)
+ }
+
+ for _, runRef := range jciRuns[hash] {
+ rparts := strings.Split(strings.TrimPrefix(runRef, "refs/jci-runs/"), "/")
+ if len(rparts) >= 2 {
+ runID := rparts[1]
+ status := getCIStatusFromRef(runRef)
+ commit.Runs = append(commit.Runs, RunInfo{
+ RunID: runID,
+ Status: status,
+ Ref: runRef,
+ })
+ }
+ }
+
+ if commit.CIStatus == "" && len(commit.Runs) > 0 {
+ commit.CIStatus = commit.Runs[len(commit.Runs)-1].Status
+ }
+
+ commits = append(commits, commit)
+ }
+
+ return commits, nil
+}
+
func showMainPage(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
fmt.Fprint(w, `<!DOCTYPE html>
diff --git a/scripts/check_go.sh b/scripts/check_go.sh
@@ -11,8 +11,8 @@ if ! command -v go >/dev/null 2>&1; then
fi
echo "Running gofmt checks..."
-gofmt -e cmd
-gofmt -e internal
+gofmt -e cmd > /dev/null
+gofmt -e internal > /dev/null
echo "Running go vet..."
go vet ./...