@@ -13,6 +13,7 @@ import (
1313 "sync"
1414
1515 "github.com/go-git/go-git/v5"
16+ "github.com/go-git/go-git/v5/plumbing"
1617 "github.com/google/wire"
1718 "github.com/samber/lo"
1819 "golang.org/x/xerrors"
@@ -56,7 +57,8 @@ type Artifact struct {
5657
5758 artifactOption artifact.Option
5859
59- commitHash string // only set when the git repository is clean
60+ isClean bool // whether git repository is clean (for caching)
61+ repoMetadata artifact.RepoMetadata // git repository metadata
6062}
6163
6264func NewArtifact (rootPath string , c cache.ArtifactCache , w Walker , opt artifact.Option ) (artifact.Artifact , error ) {
@@ -86,10 +88,14 @@ func NewArtifact(rootPath string, c cache.ArtifactCache, w Walker, opt artifact.
8688 art .logger .Debug ("Analyzing..." , log .String ("root" , art .rootPath ),
8789 lo .Ternary (opt .Original != "" , log .String ("original" , opt .Original ), log .Nil ))
8890
89- // Check if the directory is a git repository and clean
90- if hash , err := gitCommitHash (art .rootPath ); err == nil {
91- art .logger .Debug ("Using the latest commit hash for calculating cache key" , log .String ("commit_hash" , hash ))
92- art .commitHash = hash
91+ // Check if the directory is a git repository and extract metadata
92+ if art .isClean , art .repoMetadata , err = extractGitInfo (art .rootPath ); err == nil {
93+ if art .isClean {
94+ art .logger .Debug ("Using the latest commit hash for calculating cache key" ,
95+ log .String ("commit_hash" , art .repoMetadata .Commit ))
96+ } else {
97+ art .logger .Debug ("Repository is dirty, random cache key will be used" )
98+ }
9399 } else if ! errors .Is (err , git .ErrRepositoryNotExists ) {
94100 // Only log if the file path is a git repository
95101 art .logger .Debug ("Random cache key will be used" , log .Err (err ))
@@ -98,36 +104,72 @@ func NewArtifact(rootPath string, c cache.ArtifactCache, w Walker, opt artifact.
98104 return art , nil
99105}
100106
101- // gitCommitHash returns the latest commit hash if the git repository is clean, otherwise returns an error
102- func gitCommitHash (dir string ) (string , error ) {
107+ // extractGitInfo extracts git repository information including clean status and metadata
108+ // Returns clean status (for caching), metadata, and error
109+ func extractGitInfo (dir string ) (bool , artifact.RepoMetadata , error ) {
110+ var metadata artifact.RepoMetadata
111+
103112 repo , err := git .PlainOpen (dir )
104113 if err != nil {
105- return "" , xerrors .Errorf ("failed to open git repository: %w" , err )
114+ return false , metadata , xerrors .Errorf ("failed to open git repository: %w" , err )
106115 }
107116
108- // Get the working tree
109- worktree , err := repo .Worktree ()
117+ // Get HEAD commit
118+ head , err := repo .Head ()
110119 if err != nil {
111- return "" , xerrors .Errorf ("failed to get worktree : %w" , err )
120+ return false , metadata , xerrors .Errorf ("failed to get HEAD : %w" , err )
112121 }
113122
114- // Get the current status
115- status , err := worktree .Status ()
123+ commit , err := repo .CommitObject (head .Hash ())
116124 if err != nil {
117- return "" , xerrors .Errorf ("failed to get status : %w" , err )
125+ return false , metadata , xerrors .Errorf ("failed to get commit object : %w" , err )
118126 }
119127
120- if ! status .IsClean () {
121- return "" , xerrors .New ("repository is dirty" )
128+ // Extract basic commit metadata
129+ metadata .Commit = head .Hash ().String ()
130+ metadata .CommitMsg = strings .TrimSpace (commit .Message )
131+ metadata .Author = commit .Author .String ()
132+ metadata .Committer = commit .Committer .String ()
133+
134+ // Get branch name
135+ if head .Name ().IsBranch () {
136+ metadata .Branch = head .Name ().Short ()
122137 }
123138
124- // Get the HEAD commit hash
125- head , err := repo .Head ()
139+ // Get all tag names that point to HEAD
140+ if tags , err := repo .Tags (); err == nil {
141+ var headTags []string
142+ _ = tags .ForEach (func (tag * plumbing.Reference ) error {
143+ if tag .Hash () == head .Hash () {
144+ headTags = append (headTags , tag .Name ().Short ())
145+ }
146+ return nil
147+ })
148+ metadata .Tags = headTags
149+ }
150+
151+ // Get repository URL - prefer upstream, fallback to origin
152+ remoteConfig , err := repo .Remote ("upstream" )
153+ if err != nil {
154+ remoteConfig , err = repo .Remote ("origin" )
155+ }
156+ if err == nil && len (remoteConfig .Config ().URLs ) > 0 {
157+ metadata .RepoURL = remoteConfig .Config ().URLs [0 ]
158+ }
159+
160+ // Check if repository is clean for caching purposes
161+ worktree , err := repo .Worktree ()
162+ if err != nil {
163+ return false , metadata , xerrors .Errorf ("failed to get worktree: %w" , err )
164+ }
165+
166+ status , err := worktree .Status ()
126167 if err != nil {
127- return "" , xerrors .Errorf ("failed to get HEAD : %w" , err )
168+ return false , metadata , xerrors .Errorf ("failed to get status : %w" , err )
128169 }
129170
130- return head .Hash ().String (), nil
171+ // Return clean status and metadata
172+ return status .IsClean (), metadata , nil
131173}
132174
133175func (a Artifact ) Inspect (ctx context.Context ) (artifact.Reference , error ) {
@@ -138,7 +180,7 @@ func (a Artifact) Inspect(ctx context.Context) (artifact.Reference, error) {
138180 }
139181
140182 // Check if the cache exists only when it's a clean git repository
141- if a .commitHash != "" {
183+ if a .isClean && a . repoMetadata . Commit != "" {
142184 _ , missingBlobs , err := a .cache .MissingBlobs (cacheKey , []string {cacheKey })
143185 if err != nil {
144186 return artifact.Reference {}, xerrors .Errorf ("unable to get missing blob: %w" , err )
@@ -231,10 +273,11 @@ func (a Artifact) Inspect(ctx context.Context) (artifact.Reference, error) {
231273 }
232274
233275 return artifact.Reference {
234- Name : hostName ,
235- Type : a .artifactOption .Type ,
236- ID : cacheKey , // use a cache key as pseudo artifact ID
237- BlobIDs : []string {cacheKey },
276+ Name : hostName ,
277+ Type : a .artifactOption .Type ,
278+ ID : cacheKey , // use a cache key as pseudo artifact ID
279+ BlobIDs : []string {cacheKey },
280+ RepoMetadata : a .repoMetadata ,
238281 }, nil
239282}
240283
@@ -295,16 +338,16 @@ func (a Artifact) analyzeWithTraversal(ctx context.Context, root, relativePath s
295338
296339func (a Artifact ) Clean (reference artifact.Reference ) error {
297340 // Don't delete cache if it's a clean git repository
298- if a .commitHash != "" {
341+ if a .isClean && a . repoMetadata . Commit != "" {
299342 return nil
300343 }
301344 return a .cache .DeleteBlobs (reference .BlobIDs )
302345}
303346
304347func (a Artifact ) calcCacheKey () (string , error ) {
305348 // If this is a clean git repository, use the commit hash as cache key
306- if a .commitHash != "" {
307- return cache .CalcKey (a .commitHash , artifactVersion , a .analyzer .AnalyzerVersions (), a .handlerManager .Versions (), a .artifactOption )
349+ if a .isClean && a . repoMetadata . Commit != "" {
350+ return cache .CalcKey (a .repoMetadata . Commit , artifactVersion , a .analyzer .AnalyzerVersions (), a .handlerManager .Versions (), a .artifactOption )
308351 }
309352
310353 // For non-git repositories or dirty git repositories, use UUID as cache key
0 commit comments