1
0
mirror of https://github.com/prometheus-community/postgres_exporter.git synced 2025-08-06 17:22:43 +03:00
Files
Will Rouesnel 989489096e Refactor repository layout and convert build system to Mage.
This commit implements a massive refactor of the repository, and
moves the build system over to use Mage (magefile.org) which should
allow seamless building across multiple platforms.
2018-03-06 07:29:35 +10:00

358 lines
9.2 KiB
Go

// Copyright (c) 2013 Yasuhiro Matsumoto, Jason McVetta.
// This is Free Software, released under the MIT license.
// See http://mattn.mit-license.org/2013 for details.
// goveralls is a Go client for Coveralls.io.
package main
import (
"bytes"
_ "crypto/sha512"
"encoding/json"
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"time"
"golang.org/x/tools/cover"
)
/*
https://coveralls.io/docs/api_reference
*/
type Flags []string
func (a *Flags) String() string {
return strings.Join(*a, ",")
}
func (a *Flags) Set(value string) error {
*a = append(*a, value)
return nil
}
var (
extraFlags Flags
pkg = flag.String("package", "", "Go package")
verbose = flag.Bool("v", false, "Pass '-v' argument to 'go test' and output to stdout")
race = flag.Bool("race", false, "Pass '-race' argument to 'go test'")
debug = flag.Bool("debug", false, "Enable debug output")
coverprof = flag.String("coverprofile", "", "If supplied, use a go cover profile (comma separated)")
covermode = flag.String("covermode", "count", "sent as covermode argument to go test")
repotoken = flag.String("repotoken", os.Getenv("COVERALLS_TOKEN"), "Repository Token on coveralls")
endpoint = flag.String("endpoint", "https://coveralls.io", "Hostname to submit Coveralls data to")
service = flag.String("service", "travis-ci", "The CI service or other environment in which the test suite was run. ")
shallow = flag.Bool("shallow", false, "Shallow coveralls internal server errors")
ignore = flag.String("ignore", "", "Comma separated files to ignore")
show = flag.Bool("show", false, "Show which package is being tested")
)
// usage supplants package flag's Usage variable
var usage = func() {
cmd := os.Args[0]
// fmt.Fprintf(os.Stderr, "Usage of %s:\n", cmd)
s := "Usage: %s [options]\n"
fmt.Fprintf(os.Stderr, s, cmd)
flag.PrintDefaults()
}
// A SourceFile represents a source code file and its coverage data for a
// single job.
type SourceFile struct {
Name string `json:"name"` // File path of this source file
Source string `json:"source"` // Full source code of this file
Coverage []interface{} `json:"coverage"` // Requires both nulls and integers
}
// A Job represents the coverage data from a single run of a test suite.
type Job struct {
RepoToken *string `json:"repo_token,omitempty"`
ServiceJobId string `json:"service_job_id"`
ServicePullRequest string `json:"service_pull_request,omitempty"`
ServiceName string `json:"service_name"`
SourceFiles []*SourceFile `json:"source_files"`
Git *Git `json:"git,omitempty"`
RunAt time.Time `json:"run_at"`
}
// A Response is returned by the Coveralls.io API.
type Response struct {
Message string `json:"message"`
URL string `json:"url"`
Error bool `json:"error"`
}
// getPkgs returns packages for mesuring coverage. Returned packages doesn't
// contain vendor packages.
func getPkgs(pkg string) ([]string, error) {
if pkg == "" {
pkg = "./..."
}
out, err := exec.Command("go", "list", pkg).CombinedOutput()
if err != nil {
return nil, err
}
allPkgs := strings.Split(strings.Trim(string(out), "\n"), "\n")
pkgs := make([]string, 0, len(allPkgs))
for _, p := range allPkgs {
if !strings.Contains(p, "/vendor/") {
pkgs = append(pkgs, p)
}
}
return pkgs, nil
}
func getCoverage() ([]*SourceFile, error) {
if *coverprof != "" {
return parseCover(*coverprof)
}
// pkgs is packages to run tests and get coverage.
pkgs, err := getPkgs(*pkg)
if err != nil {
return nil, err
}
coverpkg := fmt.Sprintf("-coverpkg=%s", strings.Join(pkgs, ","))
var pfss [][]*cover.Profile
for _, line := range pkgs {
f, err := ioutil.TempFile("", "goveralls")
if err != nil {
return nil, err
}
f.Close()
cmd := exec.Command("go")
outBuf := new(bytes.Buffer)
cmd.Stdout = outBuf
cmd.Stderr = outBuf
coverm := *covermode
if *race {
coverm = "atomic"
}
args := []string{"go", "test", "-covermode", coverm, "-coverprofile", f.Name(), coverpkg}
if *verbose {
args = append(args, "-v")
cmd.Stdout = os.Stdout
}
if *race {
args = append(args, "-race")
}
args = append(args, extraFlags...)
args = append(args, line)
cmd.Args = args
if *show {
fmt.Println("goveralls:", line)
}
err = cmd.Run()
if err != nil {
return nil, fmt.Errorf("%v: %v", err, outBuf.String())
}
pfs, err := cover.ParseProfiles(f.Name())
if err != nil {
return nil, err
}
err = os.Remove(f.Name())
if err != nil {
return nil, err
}
pfss = append(pfss, pfs)
}
sourceFiles, err := toSF(mergeProfs(pfss))
if err != nil {
return nil, err
}
return sourceFiles, nil
}
var vscDirs = []string{".git", ".hg", ".bzr", ".svn"}
func findRepositoryRoot(dir string) (string, bool) {
for _, vcsdir := range vscDirs {
if d, err := os.Stat(filepath.Join(dir, vcsdir)); err == nil && d.IsDir() {
return dir, true
}
}
nextdir := filepath.Dir(dir)
if nextdir == dir {
return "", false
}
return findRepositoryRoot(nextdir)
}
func getCoverallsSourceFileName(name string) string {
if dir, ok := findRepositoryRoot(name); !ok {
return name
} else {
filename := strings.TrimPrefix(name, dir+string(os.PathSeparator))
return filename
}
}
func process() error {
log.SetFlags(log.Ltime | log.Lshortfile)
//
// Parse Flags
//
flag.Usage = usage
flag.Var(&extraFlags, "flags", "extra flags to the tests")
flag.Parse()
if len(flag.Args()) > 0 {
flag.Usage()
os.Exit(1)
}
//
// Setup PATH environment variable
//
paths := filepath.SplitList(os.Getenv("PATH"))
if goroot := os.Getenv("GOROOT"); goroot != "" {
paths = append(paths, filepath.Join(goroot, "bin"))
}
if gopath := os.Getenv("GOPATH"); gopath != "" {
for _, path := range filepath.SplitList(gopath) {
paths = append(paths, filepath.Join(path, "bin"))
}
}
os.Setenv("PATH", strings.Join(paths, string(filepath.ListSeparator)))
//
// Initialize Job
//
var jobId string
if travisJobId := os.Getenv("TRAVIS_JOB_ID"); travisJobId != "" {
jobId = travisJobId
} else if circleCiJobId := os.Getenv("CIRCLE_BUILD_NUM"); circleCiJobId != "" {
jobId = circleCiJobId
} else if appveyorJobId := os.Getenv("APPVEYOR_JOB_ID"); appveyorJobId != "" {
jobId = appveyorJobId
} else if semaphoreJobId := os.Getenv("SEMPAHORE_BUILD_NUMBER"); semaphoreJobId != "" {
jobId = semaphoreJobId
}
if *repotoken == "" {
repotoken = nil // remove the entry from json
}
var pullRequest string
if prNumber := os.Getenv("CIRCLE_PR_NUMBER"); prNumber != "" {
// for Circle CI (pull request from forked repo)
pullRequest = prNumber
} else if prNumber := os.Getenv("TRAVIS_PULL_REQUEST"); prNumber != "" && prNumber != "false" {
pullRequest = prNumber
} else if prURL := os.Getenv("CI_PULL_REQUEST"); prURL != "" {
// for Circle CI
pullRequest = regexp.MustCompile(`[0-9]+$`).FindString(prURL)
} else if prNumber := os.Getenv("APPVEYOR_PULL_REQUEST_NUMBER"); prNumber != "" {
pullRequest = prNumber
} else if prNumber := os.Getenv("PULL_REQUEST_NUMBER"); prNumber != "" {
pullRequest = prNumber
}
sourceFiles, err := getCoverage()
if err != nil {
return err
}
j := Job{
RunAt: time.Now(),
RepoToken: repotoken,
ServicePullRequest: pullRequest,
Git: collectGitInfo(),
SourceFiles: sourceFiles,
}
// Only include a job ID if it's known, otherwise, Coveralls looks
// for the job and can't find it.
if jobId != "" {
j.ServiceJobId = jobId
j.ServiceName = *service
}
// Ignore files
if len(*ignore) > 0 {
patterns := strings.Split(*ignore, ",")
for i, pattern := range patterns {
patterns[i] = strings.TrimSpace(pattern)
}
var files []*SourceFile
Files:
for _, file := range j.SourceFiles {
for _, pattern := range patterns {
match, err := filepath.Match(pattern, file.Name)
if err != nil {
return err
}
if match {
fmt.Printf("ignoring %s\n", file.Name)
continue Files
}
}
files = append(files, file)
}
j.SourceFiles = files
}
if *debug {
b, err := json.MarshalIndent(j, "", " ")
if err != nil {
return err
}
log.Printf("Posting data: %s", b)
}
b, err := json.Marshal(j)
if err != nil {
return err
}
params := make(url.Values)
params.Set("json", string(b))
res, err := http.PostForm(*endpoint+"/api/v1/jobs", params)
if err != nil {
return err
}
defer res.Body.Close()
bodyBytes, err := ioutil.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("Unable to read response body from coveralls: %s", err)
}
if res.StatusCode >= http.StatusInternalServerError && *shallow {
fmt.Println("coveralls server failed internally")
return nil
}
if res.StatusCode != 200 {
return fmt.Errorf("Bad response status from coveralls: %d\n%s", res.StatusCode, bodyBytes)
}
var response Response
if err = json.Unmarshal(bodyBytes, &response); err != nil {
return fmt.Errorf("Unable to unmarshal response JSON from coveralls: %s\n%s", err, bodyBytes)
}
if response.Error {
return errors.New(response.Message)
}
fmt.Println(response.Message)
fmt.Println(response.URL)
return nil
}
func main() {
if err := process(); err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
}