<commit_before>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Command git-p prints the status of pending commits on the current
// branch.
//
// git-p summarizes the status of each commit, including its review
// state in Gerrit and whether or not there are any comments or TryBot
// failures.
package main

import (
	"fmt"
	"log"
	"strings"
	"unicode/utf8"
)

// TODO: Provide a way to exclude branches (like archive/, etc)

// TODO: Do the right thing if the terminal is dumb.

const (
	// TODO: Support other repos.
	remoteUrl = "https://go.googlesource.com/go"
	project   = "go"
	gerritUrl = "https://go-review.googlesource.com"
)

func main() {
	setupPager()

	// Find the Gerrit remote name.
	remote, err := getRemote(remoteUrl)
	if err != nil {
		log.Fatal(err)
	}

	// Get commits that are available from the Gerrit remote.
	upstreams := lines(git("for-each-ref", "--format", "%(objectname)", "refs/remotes/"+remote+"/"))
	if len(upstreams) == 0 {
		log.Fatalf("no refs for remote %s", remote)
	}

	gerrit := NewGerrit(gerritUrl)

	// Pass a token through each showBranch so we can pipeline
	// fetching branch information, while displaying it in order.
	token := make(chan bool, 1)
	token <- true

	// Resolve HEAD and show it first regardless of age.
	head, _ := tryGit("symbolic-ref", "HEAD")
	if head != "" {
		token = showBranch(gerrit, head, "HEAD", remote, upstreams, token)
	}

	// Get all local branches, sorted by most recent commit date.
	branches := lines(git("for-each-ref", "--format", "%(refname)", "--sort", "-committerdate", "refs/heads/"))
	for _, branch := range branches {
		if branch == head {
			continue
		}
		token = showBranch(gerrit, branch, "", remote, upstreams, token)
	}

	<-token
}

func showBranch(gerrit *Gerrit, branch, extra string, remote string, upstreams []string, token chan bool) chan bool {
	// Get the Gerrit upstream name so we can construct full
	// Change-IDs.
	upstream := upstreamOf(branch)
	if upstream == "" {
		upstream = "refs/" + remote + "/master"
	}

	// Get commits from the branch to any upstream.
	args := []string{"rev-list", branch}
	for _, u := range upstreams {
		args = append(args, "^"+u)
	}
	commits := lines(git(args...))

	// Get Change-Ids from these commits.
	cids := changeIds(project, upstream, commits)

	// Fetch information on all of these changes.
	//
	// We need DETAILED_LABELS to get numeric values of labels.
	changes := make([]*GerritChanges, len(cids))
	for i, cid := range cids {
		// TODO: Would this be simpler with a single big OR query?
		if cid != "" {
			changes[i] = gerrit.QueryChanges("change:"+cid, printChangeOptions...)
		}
	}

	if len(changes) == 0 {
		return token
	}

	done := make(chan bool)
	go func() {
		<-token
		// Print changes.
		fmt.Printf("\x1b[1;32m%s\x1b[0m", strings.TrimPrefix(branch, "refs/heads/"))
		if extra != "" {
			fmt.Printf(" (\x1b[1;36m%s\x1b[0m)", extra)
		}
		fmt.Printf("\n")
		for i, change := range changes {
			printChange(commits[i], change)
		}
		fmt.Println()
		done <- true
	}()
	return done
}

func changeStatus(commit string, info *GerritChange) (string, []string) {
	switch info.Status {
	default:
		return fmt.Sprintf("Unknown status %q", info.Status), nil
	case "MERGED":
		return "Submitted", nil
	case "ABANDONED":
		return "Abandoned", nil
	case "DRAFT":<commit_msg>git-p: limit the pipeline depth of branch fetching<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Command git-p prints the status of pending commits on the current
// branch.
//
// git-p summarizes the status of each commit, including its review
// state in Gerrit and whether or not there are any comments or TryBot
// failures.
package main

import (
	"fmt"
	"log"
	"strings"
	"unicode/utf8"
)

// TODO: Provide a way to exclude branches (like archive/, etc)

// TODO: Do the right thing if the terminal is dumb.

const (
	// TODO: Support other repos.
	remoteUrl = "https://go.googlesource.com/go"
	project   = "go"
	gerritUrl = "https://go-review.googlesource.com"
)

func main() {
	setupPager()

	// Find the Gerrit remote name.
	remote, err := getRemote(remoteUrl)
	if err != nil {
		log.Fatal(err)
	}

	// Get commits that are available from the Gerrit remote.
	upstreams := lines(git("for-each-ref", "--format", "%(objectname)", "refs/remotes/"+remote+"/"))
	if len(upstreams) == 0 {
		log.Fatalf("no refs for remote %s", remote)
	}

	gerrit := NewGerrit(gerritUrl)

	// Pass a token through each showBranch so we can pipeline
	// fetching branch information, while displaying it in order.
	token := make(chan struct{}, 1)
	token <- struct{}{}
	// But if the output of showBranch is blocked (e.g., by
	// back-pressure from a pager), don't start new showBranches.
	// This avoids making lots of ultimately ignored requests to
	// Gerrit.
	limit := make(chan struct{}, 3)

	// Resolve HEAD and show it first regardless of age.
	head, _ := tryGit("symbolic-ref", "HEAD")
	if head != "" {
		token = showBranch(gerrit, head, "HEAD", remote, upstreams, token, limit)
	}

	// Get all local branches, sorted by most recent commit date.
	branches := lines(git("for-each-ref", "--format", "%(refname)", "--sort", "-committerdate", "refs/heads/"))
	for _, branch := range branches {
		if branch == head {
			continue
		}
		token = showBranch(gerrit, branch, "", remote, upstreams, token, limit)
	}

	<-token
}

func showBranch(gerrit *Gerrit, branch, extra string, remote string, upstreams []string, token, limit chan struct{}) chan struct{} {
	// Don't start too many showBranches.
	limit <- struct{}{}

	// Get the Gerrit upstream name so we can construct full
	// Change-IDs.
	upstream := upstreamOf(branch)
	if upstream == "" {
		upstream = "refs/" + remote + "/master"
	}

	// Get commits from the branch to any upstream.
	args := []string{"rev-list", branch}
	for _, u := range upstreams {
		args = append(args, "^"+u)
	}
	commits := lines(git(args...))

	// Get Change-Ids from these commits.
	cids := changeIds(project, upstream, commits)

	// Fetch information on all of these changes.
	//
	// We need DETAILED_LABELS to get numeric values of labels.
	changes := make([]*GerritChanges, len(cids))
	for i, cid := range cids {
		// TODO: Would this be simpler with a single big OR query?
		if cid != "" {
			changes[i] = gerrit.QueryChanges("change:"+cid, printChangeOptions...)
		}
	}

	if len(changes) == 0 {
		<-limit
		return token
	}

	done := make(chan struct{})
	go func() {
		<-token
		// Print changes.
		fmt.Printf("\x1b[1;32m%s\x1b[0m", strings.TrimPrefix(branch, "refs/heads/"))
		if extra != "" {
			fmt.Printf(" (\x1b[1;36m%s\x1b[0m)", extra)
		}
		fmt.Printf("\n")
		for i, change := range changes {
			printChange(commits[i], change)
		}
		fmt.Println()
		<-limit
		done <- struct{}{}
	}()
	return done
}

func changeStatus(commit string, info *GerritChange) (string, []string) {
	switch info.Status {
	default:
		return fmt.Sprintf("Unknown status %q", info.Status), nil
	case "MERGED":
		return "Submitted", nil
	case "ABANDONED":
		return "Abandoned", nil
	case "DRAFT":
{'fraction_non_alphanumeric': 0.14671814671814673, 'fraction_numerical': 0.005653612796469939, 'mean_word_length': 3.446965052115267, 'pattern_counts': {'":': 6, '<': 14, '<?xml version=': 0, '>': 3, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2521733', 'n_tokens_mistral': 2608, 'n_tokens_neox': 2410, 'n_words': 818}