• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gittuf / gittuf / 29552153989

17 Jul 2026 03:20AM UTC coverage: 78.033% (+0.2%) from 77.791%
29552153989

push

github

web-flow
Merge pull request #1472 from pjbgf/sha256

feat(sha256): support SHA-256 object format

179 of 220 new or added lines in 11 files covered. (81.36%)

2 existing lines in 2 files now uncovered.

12721 of 16302 relevant lines covered (78.03%)

36.22 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.31
/pkg/gitinterface/references.go
1
// Copyright The gittuf Authors
2
// SPDX-License-Identifier: Apache-2.0
3

4
package gitinterface
5

6
import (
7
        "errors"
8
        "fmt"
9
        "os"
10
        "path"
11
        "strings"
12
)
13

14
const (
15
        RefPrefix       = "refs/"
16
        BranchRefPrefix = "refs/heads/"
17
        TagRefPrefix    = "refs/tags/"
18
        RemoteRefPrefix = "refs/remotes/"
19
)
20

21
var (
22
        ErrReferenceNotFound = errors.New("requested Git reference not found")
23
)
24

25
// GetReference returns the tip of the specified Git reference.
26
func (r *Repository) GetReference(refName string) (Hash, error) {
330✔
27
        refTipID, err := r.executor("rev-parse", refName).executeString()
330✔
28
        if err != nil {
503✔
29
                if strings.Contains(err.Error(), "unknown revision or path not in the working tree") {
346✔
30
                        return r.ZeroHash(), ErrReferenceNotFound
173✔
31
                }
173✔
NEW
32
                return r.ZeroHash(), fmt.Errorf("unable to read reference '%s': %w", refName, err)
×
33
        }
34

35
        hash, err := NewHash(refTipID)
157✔
36
        if err != nil {
157✔
NEW
37
                return r.ZeroHash(), fmt.Errorf("invalid Git ID for reference '%s': %w", refName, err)
×
38
        }
×
39

40
        return hash, nil
157✔
41
}
42

43
// SetReference sets the specified reference to the provided Git ID.
44
func (r *Repository) SetReference(refName string, gitID Hash) error {
31✔
45
        _, err := r.executor("update-ref", "--create-reflog", refName, gitID.String()).executeString()
31✔
46
        if err != nil {
33✔
47
                return fmt.Errorf("unable to set Git reference '%s' to '%s': %w", refName, gitID.String(), err)
2✔
48
        }
2✔
49

50
        return nil
29✔
51
}
52

53
// DeleteReference deletes the specified Git reference.
54
func (r *Repository) DeleteReference(refName string) error {
2✔
55
        _, err := r.executor("update-ref", "-d", refName).executeString()
2✔
56
        if err != nil {
3✔
57
                return fmt.Errorf("unable to delete Git reference '%s': %w", refName, err)
1✔
58
        }
1✔
59
        return nil
1✔
60
}
61

62
// CheckAndSetReference sets the specified reference to the provided Git ID if
63
// the reference is currently set to `oldGitID`.
64
func (r *Repository) CheckAndSetReference(refName string, newGitID, oldGitID Hash) error {
197✔
65
        _, err := r.executor("update-ref", "--create-reflog", refName, newGitID.String(), oldGitID.String()).executeString()
197✔
66
        if err != nil {
198✔
67
                return fmt.Errorf("unable to set Git reference '%s' to '%s': %w", refName, newGitID.String(), err)
1✔
68
        }
1✔
69

70
        return nil
196✔
71
}
72

73
// GetSymbolicReferenceTarget returns the name of the Git reference the provided
74
// symbolic Git reference is pointing to.
75
func (r *Repository) GetSymbolicReferenceTarget(refName string) (string, error) {
41✔
76
        symTarget, err := r.executor("symbolic-ref", refName).executeString()
41✔
77
        if err != nil {
41✔
78
                return "", fmt.Errorf("unable to resolve %s: %w", refName, err)
×
79
        }
×
80

81
        return symTarget, nil
41✔
82
}
83

84
// SetSymbolicReference sets the specified symbolic reference to the specified
85
// target reference.
86
func (r *Repository) SetSymbolicReference(symRefName, targetRefName string) error {
3✔
87
        _, err := r.executor("symbolic-ref", symRefName, targetRefName).executeString()
3✔
88
        if err != nil {
3✔
89
                return fmt.Errorf("unable to set symbolic Git reference '%s' to '%s': %w", symRefName, targetRefName, err)
×
90
        }
×
91

92
        return nil
3✔
93
}
94

95
// AbsoluteReference returns the fully qualified reference path for the provided
96
// Git ref.
97
// Source: https://git-scm.com/docs/gitrevisions#Documentation/gitrevisions.txt-emltrefnamegtemegemmasterememheadsmasterememrefsheadsmasterem
98
func (r *Repository) AbsoluteReference(target string) (string, error) {
15✔
99
        _, err := os.Stat(path.Join(r.gitDirPath, target))
15✔
100
        if err == nil {
17✔
101
                if strings.HasPrefix(target, RefPrefix) {
3✔
102
                        // not symbolic ref
1✔
103
                        return target, nil
1✔
104
                }
1✔
105
                // symbolic ref such as .git/HEAD
106
                return r.GetSymbolicReferenceTarget(target)
1✔
107
        }
108

109
        // We may have a ref that isn't available locally but is still ref-prefixed.
110
        if strings.HasPrefix(target, RefPrefix) {
13✔
111
                return target, nil
×
112
        }
×
113

114
        // If target is a full ref already and it's stored in the GIT_DIR/refs
115
        // directory, we don't reach this point. Below, we handle cases where the
116
        // ref may be packed.
117

118
        // Check if custom reference
119
        customName := CustomReferenceName(target)
13✔
120
        _, err = r.GetReference(customName)
13✔
121
        if err == nil {
14✔
122
                return customName, nil
1✔
123
        }
1✔
124
        if !errors.Is(err, ErrReferenceNotFound) {
12✔
125
                return "", err
×
126
        }
×
127

128
        // Check if tag
129
        tagName := TagReferenceName(target)
12✔
130
        _, err = r.GetReference(tagName)
12✔
131
        if err == nil {
13✔
132
                return tagName, nil
1✔
133
        }
1✔
134
        if !errors.Is(err, ErrReferenceNotFound) {
11✔
135
                return "", err
×
136
        }
×
137

138
        // Check if branch
139
        branchName := BranchReferenceName(target)
11✔
140
        _, err = r.GetReference(branchName)
11✔
141
        if err == nil {
16✔
142
                return branchName, nil
5✔
143
        }
5✔
144
        if !errors.Is(err, ErrReferenceNotFound) {
6✔
145
                return "", err
×
146
        }
×
147

148
        // Check if remote tracker ref
149
        remoteRefName := RemoteReferenceName(target)
6✔
150
        _, err = r.GetReference(remoteRefName)
6✔
151
        if err == nil {
7✔
152
                return remoteRefName, nil
1✔
153
        }
1✔
154
        if !errors.Is(err, ErrReferenceNotFound) {
5✔
155
                return "", err
×
156
        }
×
157

158
        remoteRefHEAD := path.Join(remoteRefName, "HEAD")
5✔
159
        _, err = r.GetReference(remoteRefHEAD)
5✔
160
        if err == nil {
6✔
161
                return remoteRefHEAD, nil
1✔
162
        }
1✔
163
        if !errors.Is(err, ErrReferenceNotFound) {
4✔
164
                return "", err
×
165
        }
×
166

167
        return "", ErrReferenceNotFound
4✔
168
}
169

170
// RefSpec creates a Git refspec for the specified ref.  For more information on
171
// the Git refspec, please consult:
172
// https://git-scm.com/book/en/v2/Git-Internals-The-Refspec.
173
func (r *Repository) RefSpec(refName, remoteName string, fastForwardOnly bool) (string, error) {
38✔
174
        var (
38✔
175
                refPath string
38✔
176
                err     error
38✔
177
        )
38✔
178

38✔
179
        refPath = refName
38✔
180
        if !strings.HasPrefix(refPath, RefPrefix) {
45✔
181
                refPath, err = r.AbsoluteReference(refName)
7✔
182
                if err != nil {
10✔
183
                        return "", err
3✔
184
                }
3✔
185
        }
186

187
        if strings.HasPrefix(refPath, TagRefPrefix) {
39✔
188
                // TODO: check if this is correct, AFAICT tags aren't tracked in the
4✔
189
                // remotes namespace.
4✔
190
                fastForwardOnly = true
4✔
191
        }
4✔
192

193
        // local is always refPath, destination depends on remoteName
194
        localPath := refPath
35✔
195
        var remotePath string
35✔
196
        if len(remoteName) > 0 {
45✔
197
                remotePath = RemoteRef(refPath, remoteName)
10✔
198
        } else {
35✔
199
                remotePath = refPath
25✔
200
        }
25✔
201

202
        refSpecString := fmt.Sprintf("%s:%s", localPath, remotePath)
35✔
203
        if !fastForwardOnly {
43✔
204
                refSpecString = fmt.Sprintf("+%s", refSpecString)
8✔
205
        }
8✔
206

207
        return refSpecString, nil
35✔
208
}
209

210
// CustomReferenceName returns the full reference name in the form
211
// `refs/<customName>`.
212
func CustomReferenceName(customName string) string {
13✔
213
        if strings.HasPrefix(customName, RefPrefix) {
13✔
214
                return customName
×
215
        }
×
216

217
        return fmt.Sprintf("%s%s", RefPrefix, customName)
13✔
218
}
219

220
// TagReferenceName returns the full reference name for the specified tag in the
221
// form `refs/tags/<tagName>`.
222
func TagReferenceName(tagName string) string {
24✔
223
        if strings.HasPrefix(tagName, TagRefPrefix) {
25✔
224
                return tagName
1✔
225
        }
1✔
226

227
        return fmt.Sprintf("%s%s", TagRefPrefix, tagName)
23✔
228
}
229

230
// BranchReferenceName returns the full reference name for the specified branch
231
// in the form `refs/heads/<branchName>`.
232
func BranchReferenceName(branchName string) string {
72✔
233
        if strings.HasPrefix(branchName, BranchRefPrefix) {
73✔
234
                return branchName
1✔
235
        }
1✔
236

237
        return fmt.Sprintf("%s%s", BranchRefPrefix, branchName)
71✔
238
}
239

240
// RemoteReferenceName returns the full reference name in the form
241
// `refs/remotes/<name>`.
242
func RemoteReferenceName(name string) string {
10✔
243
        if strings.HasPrefix(name, RemoteRefPrefix) {
12✔
244
                return name
2✔
245
        }
2✔
246

247
        return fmt.Sprintf("%s%s", RemoteRefPrefix, name)
8✔
248
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc