github.com/ahmet2mir/goreleaser@v0.180.3-0.20210927151101-8e5ee5a9b8c5/internal/pipe/git/git.go (about) 1 package git 2 3 import ( 4 "fmt" 5 "net/url" 6 "os" 7 "os/exec" 8 "strconv" 9 "strings" 10 "time" 11 12 "github.com/apex/log" 13 14 "github.com/goreleaser/goreleaser/internal/git" 15 "github.com/goreleaser/goreleaser/internal/pipe" 16 "github.com/goreleaser/goreleaser/pkg/context" 17 ) 18 19 // Pipe that sets up git state. 20 type Pipe struct{} 21 22 func (Pipe) String() string { 23 return "getting and validating git state" 24 } 25 26 // Run the pipe. 27 func (Pipe) Run(ctx *context.Context) error { 28 if _, err := exec.LookPath("git"); err != nil { 29 return ErrNoGit 30 } 31 info, err := getInfo(ctx) 32 if err != nil { 33 return err 34 } 35 ctx.Git = info 36 log.WithField("commit", info.Commit).WithField("latest tag", info.CurrentTag).Info("building...") 37 ctx.Version = strings.TrimPrefix(ctx.Git.CurrentTag, "v") 38 return validate(ctx) 39 } 40 41 // nolint: gochecknoglobals 42 var fakeInfo = context.GitInfo{ 43 Branch: "none", 44 CurrentTag: "v0.0.0", 45 Commit: "none", 46 ShortCommit: "none", 47 FullCommit: "none", 48 } 49 50 func getInfo(ctx *context.Context) (context.GitInfo, error) { 51 if !git.IsRepo() && ctx.Snapshot { 52 log.Warn("accepting to run without a git repo because this is a snapshot") 53 return fakeInfo, nil 54 } 55 if !git.IsRepo() { 56 return context.GitInfo{}, ErrNotRepository 57 } 58 info, err := getGitInfo() 59 if err != nil && ctx.Snapshot { 60 log.WithError(err).Warn("ignoring errors because this is a snapshot") 61 if info.Commit == "" { 62 info = fakeInfo 63 } 64 return info, nil 65 } 66 return info, err 67 } 68 69 func getGitInfo() (context.GitInfo, error) { 70 branch, err := getBranch() 71 if err != nil { 72 return context.GitInfo{}, fmt.Errorf("couldn't get current branch: %w", err) 73 } 74 short, err := getShortCommit() 75 if err != nil { 76 return context.GitInfo{}, fmt.Errorf("couldn't get current commit: %w", err) 77 } 78 full, err := getFullCommit() 79 if err != nil { 80 return context.GitInfo{}, fmt.Errorf("couldn't get current commit: %w", err) 81 } 82 date, err := getCommitDate() 83 if err != nil { 84 return context.GitInfo{}, fmt.Errorf("couldn't get commit date: %w", err) 85 } 86 gitURL, err := getURL() 87 if err != nil { 88 return context.GitInfo{}, fmt.Errorf("couldn't get remote URL: %w", err) 89 } 90 91 if strings.HasPrefix(gitURL, "https://") { 92 u, err := url.Parse(gitURL) 93 if err != nil { 94 return context.GitInfo{}, fmt.Errorf("couldn't parse remote URL: %w", err) 95 } 96 u.User = nil 97 gitURL = u.String() 98 } 99 100 tag, err := getTag() 101 if err != nil { 102 return context.GitInfo{ 103 Branch: branch, 104 Commit: full, 105 FullCommit: full, 106 ShortCommit: short, 107 CommitDate: date, 108 URL: gitURL, 109 CurrentTag: "v0.0.0", 110 }, ErrNoTag 111 } 112 return context.GitInfo{ 113 Branch: branch, 114 CurrentTag: tag, 115 Commit: full, 116 FullCommit: full, 117 ShortCommit: short, 118 CommitDate: date, 119 URL: gitURL, 120 }, nil 121 } 122 123 func validate(ctx *context.Context) error { 124 if ctx.Snapshot { 125 return pipe.ErrSnapshotEnabled 126 } 127 if ctx.SkipValidate { 128 return pipe.ErrSkipValidateEnabled 129 } 130 if _, err := os.Stat(".git/shallow"); err == nil { 131 log.Warn("running against a shallow clone - check your CI documentation at https://goreleaser.com/ci") 132 } 133 if err := CheckDirty(); err != nil { 134 return err 135 } 136 _, err := git.Clean(git.Run("describe", "--exact-match", "--tags", "--match", ctx.Git.CurrentTag)) 137 if err != nil { 138 return ErrWrongRef{ 139 commit: ctx.Git.Commit, 140 tag: ctx.Git.CurrentTag, 141 } 142 } 143 return nil 144 } 145 146 // CheckDirty returns an error if the current git repository is dirty. 147 func CheckDirty() error { 148 out, err := git.Run("status", "--porcelain") 149 if strings.TrimSpace(out) != "" || err != nil { 150 return ErrDirty{status: out} 151 } 152 return nil 153 } 154 155 func getBranch() (string, error) { 156 return git.Clean(git.Run("rev-parse", "--abbrev-ref", "HEAD", "--quiet")) 157 } 158 159 func getCommitDate() (time.Time, error) { 160 ct, err := git.Clean(git.Run("show", "--format='%ct'", "HEAD", "--quiet")) 161 if err != nil { 162 return time.Time{}, err 163 } 164 if ct == "" { 165 return time.Time{}, nil 166 } 167 i, err := strconv.ParseInt(ct, 10, 64) 168 if err != nil { 169 return time.Time{}, err 170 } 171 t := time.Unix(i, 0).UTC() 172 return t, nil 173 } 174 175 func getShortCommit() (string, error) { 176 return git.Clean(git.Run("show", "--format='%h'", "HEAD", "--quiet")) 177 } 178 179 func getFullCommit() (string, error) { 180 return git.Clean(git.Run("show", "--format='%H'", "HEAD", "--quiet")) 181 } 182 183 func getTag() (string, error) { 184 var tag string 185 var err error 186 for _, fn := range []func() (string, error){ 187 func() (string, error) { 188 return os.Getenv("GORELEASER_CURRENT_TAG"), nil 189 }, 190 func() (string, error) { 191 return git.Clean(git.Run("tag", "--points-at", "HEAD", "--sort", "-version:refname")) 192 }, 193 func() (string, error) { 194 return git.Clean(git.Run("describe", "--tags", "--abbrev=0")) 195 }, 196 } { 197 tag, err = fn() 198 if tag != "" || err != nil { 199 return tag, err 200 } 201 } 202 203 return tag, err 204 } 205 206 func getURL() (string, error) { 207 return git.Clean(git.Run("ls-remote", "--get-url")) 208 }