Skip to content

Commit 0f31095

Browse files
bepclaude
andcommitted
Refactor: Store SHA256 checksums in BuildArchPath
Instead of parsing the checksums file in the publish command, store SHA256 values directly in BuildArchPath during the release step. This makes the checksum data available programmatically and avoids fragile file parsing. - Add SHA256 field to BuildArchPath struct - Update CreateChecksumLines to return ChecksumResult with map - Update release command to populate SHA256 in ArchsCompiled - Simplify publish command to use archPath.SHA256 directly Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 962988e commit 0f31095

File tree

5 files changed

+66
-78
lines changed

5 files changed

+66
-78
lines changed

cmd/publishcmd/publish.go

Lines changed: 17 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -164,38 +164,32 @@ func (p *Publisher) updateHomebrewCask(
164164
version := strings.TrimPrefix(p.core.Tag, "v")
165165

166166
// Find the first .pkg archive matching the path pattern.
167-
pkgFilename, err := p.findPkgArchive(release, caskSettings)
167+
pkgInfo, err := p.findPkgArchive(release, caskSettings)
168168
if err != nil {
169169
return err
170170
}
171171

172-
logCtx.WithField("pkg", pkgFilename).Log(logg.String("Found pkg archive"))
173-
174-
// Get SHA256 from checksums file.
175-
sha256, err := p.getSHA256ForFile(pkgFilename)
176-
if err != nil {
177-
return fmt.Errorf("failed to get SHA256 for %s: %v", pkgFilename, err)
178-
}
172+
logCtx.WithField("pkg", pkgInfo.Name).Log(logg.String("Found pkg archive"))
179173

180174
// Build download URL.
181175
downloadURL := fmt.Sprintf(
182176
"https://github.com/%s/%s/releases/download/%s/%s",
183177
releaseSettings.RepositoryOwner,
184178
releaseSettings.Repository,
185179
p.core.Tag,
186-
pkgFilename,
180+
pkgInfo.Name,
187181
)
188182

189183
// Build cask context.
190184
caskCtx := HomebrewCaskContext{
191185
Name: caskSettings.Name,
192186
DisplayName: p.core.Config.Project,
193187
Version: version,
194-
SHA256: sha256,
188+
SHA256: pkgInfo.SHA256,
195189
URL: downloadURL,
196190
Description: caskSettings.Description,
197191
Homepage: caskSettings.Homepage,
198-
PkgFilename: pkgFilename,
192+
PkgFilename: pkgInfo.Name,
199193
BundleIdentifier: caskSettings.BundleIdentifier,
200194
}
201195

@@ -253,8 +247,14 @@ func (p *Publisher) updateHomebrewCask(
253247
return nil
254248
}
255249

250+
// pkgArchiveInfo contains information about a .pkg archive.
251+
type pkgArchiveInfo struct {
252+
Name string
253+
SHA256 string
254+
}
255+
256256
// findPkgArchive finds the first .pkg archive for darwin matching the path pattern.
257-
func (p *Publisher) findPkgArchive(release config.Release, caskSettings config.HomebrewCaskSettings) (string, error) {
257+
func (p *Publisher) findPkgArchive(release config.Release, caskSettings config.HomebrewCaskSettings) (pkgArchiveInfo, error) {
258258
pathMatcher := caskSettings.PathCompiled
259259

260260
for _, archPath := range release.ArchsCompiled {
@@ -270,51 +270,12 @@ func (p *Publisher) findPkgArchive(release config.Release, caskSettings config.H
270270

271271
// Check if it's a .pkg file.
272272
if strings.HasSuffix(archPath.Name, ".pkg") {
273-
return archPath.Name, nil
274-
}
275-
}
276-
277-
return "", fmt.Errorf("no .pkg archive found for darwin matching path pattern %q", caskSettings.Path)
278-
}
279-
280-
// getSHA256ForFile extracts the SHA256 checksum for a specific file from the checksums file.
281-
func (p *Publisher) getSHA256ForFile(filename string) (string, error) {
282-
// Find the release directory.
283-
release := p.core.Config.Releases[0]
284-
releaseDir := filepath.Join(
285-
p.core.DistDir,
286-
p.core.Config.Project,
287-
p.core.Tag,
288-
p.core.DistRootReleases,
289-
filepath.FromSlash(release.Path),
290-
)
291-
292-
// Checksums filename follows the pattern from releasecmd.
293-
checksumFilename := fmt.Sprintf("%s_%s_checksums.txt",
294-
p.core.Config.Project,
295-
strings.TrimPrefix(p.core.Tag, "v"),
296-
)
297-
checksumPath := filepath.Join(releaseDir, checksumFilename)
298-
299-
content, err := os.ReadFile(checksumPath)
300-
if err != nil {
301-
return "", fmt.Errorf("failed to read checksums file %s: %v", checksumPath, err)
302-
}
303-
304-
// Parse checksums file (format: "sha256 filename").
305-
for _, line := range strings.Split(string(content), "\n") {
306-
line = strings.TrimSpace(line)
307-
if line == "" {
308-
continue
309-
}
310-
parts := strings.SplitN(line, " ", 2)
311-
if len(parts) != 2 {
312-
continue
313-
}
314-
if parts[1] == filename {
315-
return parts[0], nil
273+
return pkgArchiveInfo{
274+
Name: archPath.Name,
275+
SHA256: archPath.SHA256,
276+
}, nil
316277
}
317278
}
318279

319-
return "", fmt.Errorf("checksum not found for file %s in %s", filename, checksumPath)
280+
return pkgArchiveInfo{}, fmt.Errorf("no .pkg archive found for darwin matching path pattern %q", caskSettings.Path)
320281
}

cmd/releasecmd/release.go

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,16 @@ func (b *Releaser) Exec(ctx context.Context, args []string) error {
118118
logCtx := b.infoLog.WithFields(logFields)
119119

120120
logCtx.Log(logg.String("Finding releases"))
121-
releaseMatches := b.core.Config.FindReleases(b.core.PathsReleasesCompiled)
122121

123-
for _, release := range releaseMatches {
122+
// Iterate over the original releases slice so we can update SHA256 checksums.
123+
for i := range b.core.Config.Releases {
124+
release := &b.core.Config.Releases[i]
125+
if b.core.PathsReleasesCompiled != nil && !b.core.PathsReleasesCompiled.Match(release.Path) {
126+
continue
127+
}
124128
if err := b.handleRelease(ctx, logCtx, release); err != nil {
125129
return err
126130
}
127-
128131
}
129132

130133
return nil
@@ -138,7 +141,7 @@ type releaseContext struct {
138141
Info releases.ReleaseInfo
139142
}
140143

141-
func (b *Releaser) handleRelease(ctx context.Context, logCtx logg.LevelLogger, release config.Release) error {
144+
func (b *Releaser) handleRelease(ctx context.Context, logCtx logg.LevelLogger, release *config.Release) error {
142145
releaseDir := filepath.Join(
143146
b.core.DistDir,
144147
b.core.Config.Project,
@@ -209,11 +212,18 @@ func (b *Releaser) handleRelease(ctx context.Context, logCtx logg.LevelLogger, r
209212

210213
if len(archiveFilenames) > 0 {
211214

212-
checksumFilename, err := b.generateChecksumTxt(rctx, archiveFilenames...)
215+
checksumFilename, checksums, err := b.generateChecksumTxt(rctx, archiveFilenames...)
213216
if err != nil {
214217
return err
215218
}
216219

220+
// Store SHA256 checksums in the ArchsCompiled for use by the publish command.
221+
for i := range release.ArchsCompiled {
222+
if sha, ok := checksums[release.ArchsCompiled[i].Name]; ok {
223+
release.ArchsCompiled[i].SHA256 = sha
224+
}
225+
}
226+
217227
archiveFilenames = append(archiveFilenames, checksumFilename)
218228

219229
logCtx.Logf("Prepared %d files to archive: %v", len(archiveFilenames), archiveFilenames)
@@ -318,7 +328,6 @@ func (b *Releaser) generateReleaseNotes(rctx releaseContext) (string, error) {
318328
}
319329
return "", 0, false
320330
})
321-
322331
if err != nil {
323332
return "", err
324333
}
@@ -356,7 +365,6 @@ func (b *Releaser) generateReleaseNotes(rctx releaseContext) (string, error) {
356365
}
357366
} else {
358367
t = staticfiles.ReleaseNotesTemplate
359-
360368
}
361369

362370
if err := t.Execute(f, rnc); err != nil {
@@ -365,7 +373,6 @@ func (b *Releaser) generateReleaseNotes(rctx releaseContext) (string, error) {
365373

366374
return nil
367375
}()
368-
369376
if err != nil {
370377
return "", fmt.Errorf("%s: failed to create release notes file %q: %s", commandName, releaseNotesFilename, err)
371378
}
@@ -375,11 +382,11 @@ func (b *Releaser) generateReleaseNotes(rctx releaseContext) (string, error) {
375382
return releaseNotesFilename, nil
376383
}
377384

378-
func (b *Releaser) generateChecksumTxt(rctx releaseContext, archiveFilenames ...string) (string, error) {
385+
func (b *Releaser) generateChecksumTxt(rctx releaseContext, archiveFilenames ...string) (string, map[string]string, error) {
379386
// Create a checksums.txt file.
380-
checksumLines, err := releases.CreateChecksumLines(b.core.Workforce, archiveFilenames...)
387+
checksumResult, err := releases.CreateChecksumLines(b.core.Workforce, archiveFilenames...)
381388
if err != nil {
382-
return "", err
389+
return "", nil, err
383390
}
384391
// This is what Hugo got out of the box from Goreleaser. No settings for now.
385392
name := fmt.Sprintf("%s_%s_checksums.txt", rctx.Info.Project, strings.TrimPrefix(rctx.Info.Tag, "v"))
@@ -392,7 +399,7 @@ func (b *Releaser) generateChecksumTxt(rctx releaseContext, archiveFilenames ...
392399
}
393400
defer f.Close()
394401

395-
for _, line := range checksumLines {
402+
for _, line := range checksumResult.Lines {
396403
_, err := f.WriteString(line + "\n")
397404
if err != nil {
398405
return err
@@ -401,12 +408,11 @@ func (b *Releaser) generateChecksumTxt(rctx releaseContext, archiveFilenames ...
401408

402409
return nil
403410
}()
404-
405411
if err != nil {
406-
return "", fmt.Errorf("%s: failed to create checksum file %q: %s", commandName, checksumFilename, err)
412+
return "", nil, fmt.Errorf("%s: failed to create checksum file %q: %s", commandName, checksumFilename, err)
407413
}
408414

409415
rctx.Log.WithField("filename", checksumFilename).Log(logg.String("Created checksum file"))
410416

411-
return checksumFilename, nil
417+
return checksumFilename, checksumResult.Checksums, nil
412418
}

internal/config/archive_config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ type BuildArchPath struct {
7171

7272
// Any archive aliase names, with the extension.
7373
Aliases []string `json:"aliases"`
74+
75+
// SHA256 is the SHA256 checksum of the archive file.
76+
// This is populated by the release command after computing checksums.
77+
SHA256 string `json:"-"`
7478
}
7579

7680
type ArchiveSettings struct {

internal/releases/checksums.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,21 @@ import (
2727
"github.com/bep/workers"
2828
)
2929

30+
// ChecksumResult contains the checksum lines and a map of filename to checksum.
31+
type ChecksumResult struct {
32+
// Lines contains the checksum lines in "sha256 filename" format.
33+
Lines []string
34+
// Checksums maps base filename to its SHA256 checksum.
35+
Checksums map[string]string
36+
}
37+
3038
// CreateChecksumLines writes the SHA256 checksums as lowercase hex digits followed by
3139
// two spaces and then the base of filename and returns a sorted slice.
32-
func CreateChecksumLines(w *workers.Workforce, filenames ...string) ([]string, error) {
40+
// It also returns a map of base filename -> checksum for programmatic access.
41+
func CreateChecksumLines(w *workers.Workforce, filenames ...string) (ChecksumResult, error) {
3342
var mu sync.Mutex
34-
var result []string
43+
var result ChecksumResult
44+
result.Checksums = make(map[string]string)
3545

3646
r, _ := w.Start(context.Background())
3747

@@ -55,19 +65,21 @@ func CreateChecksumLines(w *workers.Workforce, filenames ...string) ([]string, e
5565
if err != nil {
5666
return err
5767
}
68+
baseName := filepath.Base(filename)
5869
mu.Lock()
59-
result = append(result, checksum+" "+filepath.Base(filename))
70+
result.Lines = append(result.Lines, checksum+" "+baseName)
71+
result.Checksums[baseName] = checksum
6072
mu.Unlock()
6173

6274
return nil
6375
})
6476
}
6577

6678
if err := r.Wait(); err != nil {
67-
return nil, err
79+
return ChecksumResult{}, err
6880
}
6981

70-
sort.Strings(result)
82+
sort.Strings(result.Lines)
7183

7284
return result, nil
7385
}

internal/releases/checksums_test.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ func TestCreateChecksumLines(t *testing.T) {
4545
filenames = append(filenames, filename)
4646
}
4747

48-
checksums, err := CreateChecksumLines(w, filenames...)
48+
result, err := CreateChecksumLines(w, filenames...)
4949
c.Assert(err, qt.IsNil)
50-
c.Assert(checksums, qt.DeepEquals, []string{
50+
c.Assert(result.Lines, qt.DeepEquals, []string{
5151
"196373310827669cb58f4c688eb27aabc40e600dc98615bd329f410ab7430cff file6.txt",
5252
"47ea70cf08872bdb4afad3432b01d963ac7d165f6b575cd72ef47498f4459a90 file3.txt",
5353
"4e74512f1d8e5016f7a9d9eaebbeedb1549fed5b63428b736eecfea98292d75f file9.txt",
@@ -59,4 +59,9 @@ func TestCreateChecksumLines(t *testing.T) {
5959
"bd4c6c665a1b8b4745bcfd3d744ea37488237108681a8ba4486a76126327d3f2 file8.txt",
6060
"e361a57a7406adee653f1dcff660d84f0ca302907747af2a387f67821acfce33 file4.txt",
6161
})
62+
63+
// Verify the checksums map for programmatic access.
64+
c.Assert(result.Checksums["file0.txt"], qt.Equals, "5a936ee19a0cf3c70d8cb0006111b7a52f45ec01703e0af8cdc8c6d81ac5850c")
65+
c.Assert(result.Checksums["file9.txt"], qt.Equals, "4e74512f1d8e5016f7a9d9eaebbeedb1549fed5b63428b736eecfea98292d75f")
66+
c.Assert(len(result.Checksums), qt.Equals, 10)
6267
}

0 commit comments

Comments
 (0)