1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2024 Datadog, Inc.
package utils
import (
"errors"
"os/exec"
"regexp"
"strconv"
"strings"
"time"
)
// localGitData holds various pieces of information about the local Git repository,
// including the source root, repository URL, branch, commit SHA, author and committer details, and commit message.
type localGitData struct {
SourceRoot string
RepositoryURL string
Branch string
CommitSha string
AuthorDate time.Time
AuthorName string
AuthorEmail string
CommitterDate time.Time
CommitterName string
CommitterEmail string
CommitMessage string
}
// regexpSensitiveInfo is a regular expression used to match and filter out sensitive information from URLs.
var regexpSensitiveInfo = regexp.MustCompile("(https?://|ssh?://)[^/]*@")
// getLocalGitData retrieves information about the local Git repository from the current HEAD.
// It gathers details such as the repository URL, current branch, latest commit SHA, author and committer details, and commit message.
//
// Returns:
//
// A localGitData struct populated with the retrieved Git data.
// An error if any Git command fails or the retrieved data is incomplete.
func getLocalGitData() (localGitData, error) {
gitData := localGitData{}
// Extract the absolute path to the Git directory
out, err := exec.Command("git", "rev-parse", "--absolute-git-dir").Output()
if err == nil {
gitData.SourceRoot = strings.ReplaceAll(strings.Trim(string(out), "\n"), ".git", "")
}
// Extract the repository URL
out, err = exec.Command("git", "ls-remote", "--get-url").Output()
if err == nil {
gitData.RepositoryURL = filterSensitiveInfo(strings.Trim(string(out), "\n"))
}
// Extract the current branch name
out, err = exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD").Output()
if err == nil {
gitData.Branch = strings.Trim(string(out), "\n")
}
// Get commit details from the latest commit using git log (git log -1 --pretty='%H","%aI","%an","%ae","%cI","%cn","%ce","%B')
out, err = exec.Command("git", "log", "-1", "--pretty=%H\",\"%at\",\"%an\",\"%ae\",\"%ct\",\"%cn\",\"%ce\",\"%B").Output()
if err != nil {
return gitData, err
}
// Split the output into individual components
outArray := strings.Split(string(out), "\",\"")
if len(outArray) < 8 {
return gitData, errors.New("git log failed")
}
// Parse author and committer dates from Unix timestamp
authorUnixDate, _ := strconv.ParseInt(outArray[1], 10, 64)
committerUnixDate, _ := strconv.ParseInt(outArray[4], 10, 64)
// Populate the localGitData struct with the parsed information
gitData.CommitSha = outArray[0]
gitData.AuthorDate = time.Unix(authorUnixDate, 0)
gitData.AuthorName = outArray[2]
gitData.AuthorEmail = outArray[3]
gitData.CommitterDate = time.Unix(committerUnixDate, 0)
gitData.CommitterName = outArray[5]
gitData.CommitterEmail = outArray[6]
gitData.CommitMessage = strings.Trim(outArray[7], "\n")
return gitData, nil
}
// filterSensitiveInfo removes sensitive information from a given URL using a regular expression.
// It replaces the user credentials part of the URL (if present) with an empty string.
//
// Parameters:
//
// url - The URL string from which sensitive information should be filtered out.
//
// Returns:
//
// The sanitized URL string with sensitive information removed.
func filterSensitiveInfo(url string) string {
return string(regexpSensitiveInfo.ReplaceAll([]byte(url), []byte("$1"))[:])
}
|