<commit_before>// Copyright (c) 2016 <NAME>
//
// This file is part of the Ascent Library.
//
// The Ascent Library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Ascent Library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with the Ascent Library.  If not, see <http://www.gnu.org/licenses/>.

//
// A Git hook script to verify what is about to be pushed.  Called by "git
// push" after it has checked the remote status, but before anything has been
// pushed.  If this script exits with a non-zero status nothing will be pushed.
//
// Information about the commits which are being pushed is supplied as lines to
// the standard input in the form:
//
//   <local ref> <local sha1> <remote ref> <remote sha1>
//

package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strings"
)

func main() {
	var localRef string
	var localSha string
	var remoteRef string
	var remoteSha string

	// Scan the input parameters passed to the pre-push script. Stdin would be
	// empty if there are no commits to send.
	count, errScan := fmt.Scanf("%s %s %s %s", &localRef, &localSha, &remoteRef,
		&remoteSha)
	if count == 0 {
		return
	}
	if errScan != nil || count != 4 {
		log.Fatalf("git input parameters are in unexpected format")
	}

	// Multiple commits can be sent in one push, so figure out the uncommited
	// commits.
	shalistCmd := exec.Command("git", "log", `--format=%H`,
		fmt.Sprintf("%s..%s", remoteSha, localSha))
	stdout, errShalist := shalistCmd.Output()
	if errShalist != nil {
		log.Fatalf("could not find uncommitted commit ids: %v", errShalist)
	}

	// Accumulate all errors and report them once.
	var errList []error
	defer func() {
		if len(errList) == 0 {
			return
		}
		fmt.Fprintln(os.Stderr)
		for _, err := range errList {
			fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		}
		fmt.Fprintln(os.Stderr)
		os.Exit(1)
	}()

	// Verify commit message format in every commit.
	for _, sha := range strings.Fields(string(stdout)) {
		commitCmd := exec.Command("git", "log", "-n", "1", sha)
		commit, errCommit := commitCmd.Output()
		if errCommit != nil {
			log.Fatalf("could not find commit message for %s: %v", sha, errCommit)
		}
		// Check the commit for compliance.
		if errs := CheckCommitMessage(sha, string(commit)); errs != nil {
			errList = append(errList, errs...)
		}
	}
}

// CheckCommitMessage verifies that commit message format includes the commit
// message template fields.
//
// See git commit template file templates/git-commit-template.txt
func CheckCommitMessage(sha, commit string) []error {
	// Regular expressions to match the fields from git commit template.
	reviewersRe := regexp.MustCompile(`^\s*Reviewers\s+:\s*\S+.*$`)
	testsRe := regexp.MustCompile(`^\s*Tests Run\s+:.*$`)
	ticketsRe := regexp.MustCompile(`^\s*Tickets Resolved\s+:.*$`)

	reviewers, tests, tickets := 0, 0, 0
	reviewersLine, testsLine, ticketsLine := -1, -1, -1
	reviewersColon, testsColon, ticketsColon := 0, 0, 0

	lines := strings.Split(commit, "\n")
	for ii, line := range lines {
		switch {
		case reviewersRe.MatchString(line):
			reviewers++
			reviewersLine = ii
			reviewersColon = strings.IndexRune(line, ':')
		case testsRe.MatchString(line):
			tests++
			testsLine = ii
			testsColon = strings.IndexRune(line, ':')
		case ticketsRe.MatchString(line):
			tickets++
			ticketsLine = ii
			ticketsColon = strings.IndexRune(line, ':')
		}
	}

	var errList []error
	if reviewers == 0 {<commit_msg>Ignore git-subtree operations from git pre-push hook.<commit_after>// Copyright (c) 2016 <NAME>
//
// This file is part of the Ascent Library.
//
// The Ascent Library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Ascent Library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with the Ascent Library.  If not, see <http://www.gnu.org/licenses/>.

//
// A Git hook script to verify what is about to be pushed.  Called by "git
// push" after it has checked the remote status, but before anything has been
// pushed.  If this script exits with a non-zero status nothing will be pushed.
//
// Information about the commits which are being pushed is supplied as lines to
// the standard input in the form:
//
//   <local ref> <local sha1> <remote ref> <remote sha1>
//

package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strings"
)

func main() {
	var localRef string
	var localSha string
	var remoteRef string
	var remoteSha string

	// Scan the input parameters passed to the pre-push script. Stdin would be
	// empty if there are no commits to send.
	count, errScan := fmt.Scanf("%s %s %s %s", &localRef, &localSha, &remoteRef,
		&remoteSha)
	if count == 0 {
		return
	}
	if errScan != nil || count != 4 {
		log.Fatalf("git input parameters are in unexpected format")
	}

	// Multiple commits can be sent in one push, so figure out the uncommited
	// commits.
	shalistCmd := exec.Command("git", "log", "--no-merges", `--format=%H`,
		fmt.Sprintf("%s..%s", remoteSha, localSha))
	stdout, errShalist := shalistCmd.Output()
	if errShalist != nil {
		log.Fatalf("could not find uncommitted commit ids: %v", errShalist)
	}

	// Accumulate all errors and report them once.
	var errList []error
	defer func() {
		if len(errList) == 0 {
			return
		}
		fmt.Fprintln(os.Stderr)
		for _, err := range errList {
			fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		}
		fmt.Fprintln(os.Stderr)
		os.Exit(1)
	}()

	// Verify commit message format in every commit.
	for _, sha := range strings.Fields(string(stdout)) {
		commitCmd := exec.Command("git", "log", "-n", "1", sha)
		commit, errCommit := commitCmd.Output()
		if errCommit != nil {
			log.Fatalf("could not find commit message for %s: %v", sha, errCommit)
		}
		// Check the commit for compliance.
		if errs := CheckCommitMessage(sha, string(commit)); errs != nil {
			errList = append(errList, errs...)
		}
	}
}

// CheckCommitMessage verifies that commit message format includes the commit
// message template fields.
//
// See git commit template file templates/git-commit-template.txt
func CheckCommitMessage(sha, commit string) []error {
	// Regular expressions to match the fields from git commit template.
	reviewersRe := regexp.MustCompile(`^\s*Reviewers\s+:\s*\S+.*$`)
	testsRe := regexp.MustCompile(`^\s*Tests Run\s+:.*$`)
	ticketsRe := regexp.MustCompile(`^\s*Tickets Resolved\s+:.*$`)
	subtreeRe := regexp.MustCompile(`^\s*git-subtree-.*$`)

	reviewers, tests, tickets := 0, 0, 0
	reviewersLine, testsLine, ticketsLine := -1, -1, -1
	reviewersColon, testsColon, ticketsColon := 0, 0, 0

	lines := strings.Split(commit, "\n")
	for ii, line := range lines {
		switch {
		case subtreeRe.MatchString(line):
			// Ignore git-subtree commits.
			return nil
		case reviewersRe.MatchString(line):
			reviewers++
			reviewersLine = ii
			reviewersColon = strings.IndexRune(line, ':')
		case testsRe.MatchString(line):
			tests++
			testsLine = ii
			testsColon = strings.IndexRune(line, ':')
		case ticketsRe.MatchString(line):
			tickets++
			ticketsLine = ii
			ticketsColon = strings.IndexRune(line, ':')
		}
	}

	var errList []error
	if reviewers == 0 {
{'fraction_non_alphanumeric': 0.12763831647308604, 'fraction_numerical': 0.005495191707256151, 'mean_word_length': 3.5140924464487036, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '3590472', 'n_tokens_mistral': 2715, 'n_tokens_neox': 2551, 'n_words': 932}