Skip to content

Commit 322455b

Browse files
authored
Merge pull request #40 from Nightapes/checksum
feat(assets): calculate checksum for all assets and upload it
2 parents cc957cb + 400a25f commit 322455b

File tree

14 files changed

+417
-207
lines changed

14 files changed

+417
-207
lines changed

cmd/go-semantic-release/commands/zip.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
)
77

88
func init() {
9+
zipCmd.Flags().StringP("algorithm", "a", "sha256", "Algorithm for checksum (crc32,md5,sha1,sha224,sha384,sha256,sha512)")
910
rootCmd.AddCommand(zipCmd)
1011
}
1112

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ require (
1717
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b // indirect
1818
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
1919
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae // indirect
20-
google.golang.org/appengine v1.6.5 // indirect
20+
google.golang.org/appengine v1.6.5
2121
gopkg.in/src-d/go-billy.v4 v4.3.2
2222
gopkg.in/src-d/go-git.v4 v4.13.1
2323
gopkg.in/yaml.v2 v2.2.8

internal/assets/asset.go

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package assets
2+
3+
import (
4+
"archive/zip"
5+
"crypto/md5"
6+
"crypto/sha1"
7+
"crypto/sha256"
8+
"crypto/sha512"
9+
"encoding/hex"
10+
"hash"
11+
"hash/crc32"
12+
"io"
13+
"io/ioutil"
14+
"os"
15+
"path"
16+
"path/filepath"
17+
18+
"github.com/Nightapes/go-semantic-release/pkg/config"
19+
"github.com/pkg/errors"
20+
log "github.com/sirupsen/logrus"
21+
)
22+
23+
// Asset struct
24+
type Asset struct {
25+
name string
26+
path string
27+
algorithm string
28+
isCompressed bool
29+
}
30+
31+
//NewAsset from a config
32+
func NewAsset(repository string, assetConfig config.Asset, algorithm string) (*Asset, error) {
33+
34+
filePath := assetConfig.Path
35+
if assetConfig.Name != "" && assetConfig.Path == "" {
36+
filePath = assetConfig.Name
37+
log.Warn("Name is deprecated. Please update your config. See https://nightapes.github.io/go-semantic-release/")
38+
}
39+
40+
realPath := path.Join(repository, filePath)
41+
42+
file, err := os.Open(realPath)
43+
if err != nil {
44+
file.Close()
45+
return nil, errors.Wrapf(err, "Could not open file %s", realPath)
46+
}
47+
defer file.Close()
48+
49+
name := assetConfig.Rename
50+
if assetConfig.Rename == "" {
51+
info, _ := file.Stat()
52+
name = info.Name()
53+
}
54+
55+
asset := &Asset{
56+
path: realPath,
57+
name: name,
58+
isCompressed: assetConfig.Compress,
59+
algorithm: algorithm,
60+
}
61+
62+
return asset, nil
63+
}
64+
65+
func (a *Asset) getChecksum() (string, error) {
66+
log.Debugf("Calculating checksum for %s", a.path)
67+
file, err := os.Open(a.path)
68+
if err != nil {
69+
return "", errors.Wrapf(err, "Failed to open file %s to calculate checksum", a.name)
70+
}
71+
defer file.Close() // nolint: errcheck
72+
var hash hash.Hash
73+
switch a.algorithm {
74+
case "crc32":
75+
hash = crc32.NewIEEE()
76+
case "md5":
77+
hash = md5.New()
78+
case "sha1":
79+
hash = sha1.New()
80+
case "sha224":
81+
hash = sha256.New224()
82+
case "sha384":
83+
hash = sha512.New384()
84+
case "sha256":
85+
hash = sha256.New()
86+
case "sha512":
87+
hash = sha512.New()
88+
default:
89+
hash = sha256.New()
90+
}
91+
_, err = io.Copy(hash, file)
92+
if err != nil {
93+
return "", err
94+
}
95+
return hex.EncodeToString(hash.Sum(nil)), nil
96+
}
97+
98+
// GetPath where the file is located, if zipped true, it will compress it and give you the new location
99+
func (a *Asset) GetPath() (string, error) {
100+
if a.isCompressed {
101+
return a.zipFile()
102+
}
103+
return a.path, nil
104+
}
105+
106+
// GetName of asset
107+
func (a *Asset) GetName() string {
108+
return a.name
109+
}
110+
111+
// IsCompressed return true if file was zipped
112+
func (a *Asset) IsCompressed() bool {
113+
return a.isCompressed
114+
}
115+
116+
// ZipFile compress given file in zip format
117+
func (a *Asset) zipFile() (string, error) {
118+
119+
path := a.path
120+
fileToZip, err := os.Open(path)
121+
if err != nil {
122+
return "", errors.Wrapf(err, "Could not open file %s", path)
123+
}
124+
defer fileToZip.Close()
125+
126+
zipFile, err := ioutil.TempFile(os.TempDir(), "asset.*.zip")
127+
128+
if err != nil {
129+
return "", errors.Wrap(err, "Could not generate tmp file")
130+
}
131+
log.Debugf("Created zipfile %s", zipFile.Name())
132+
133+
fileToZipInfo, err := fileToZip.Stat()
134+
if err != nil {
135+
return "", errors.Wrap(err, "Could not read file infos")
136+
}
137+
138+
zipWriter := zip.NewWriter(zipFile)
139+
defer zipWriter.Close()
140+
141+
fileToZipHeader, err := zip.FileInfoHeader(fileToZipInfo)
142+
if err != nil {
143+
return "", errors.Wrap(err, "Could not add file infos to zip handler")
144+
}
145+
146+
fileToZipHeader.Name = fileToZipInfo.Name()
147+
148+
fileToZipWriter, err := zipWriter.CreateHeader(fileToZipHeader)
149+
if err != nil {
150+
return "", errors.Wrap(err, "Could not create zip header")
151+
}
152+
153+
if _, err = io.Copy(fileToZipWriter, fileToZip); err != nil {
154+
return "", errors.Wrap(err, "Could not zip file")
155+
}
156+
if err := zipFile.Close(); err != nil {
157+
return "", errors.Wrap(err, "Could not close file")
158+
}
159+
return filepath.Abs(fileToZipInfo.Name())
160+
}

internal/assets/assets.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package assets
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"io/ioutil"
7+
"os"
8+
"path/filepath"
9+
10+
"github.com/Nightapes/go-semantic-release/pkg/config"
11+
"github.com/pkg/errors"
12+
)
13+
14+
// Set struct
15+
type Set struct {
16+
Assets []*Asset
17+
repository string
18+
algorithm string
19+
}
20+
21+
//New container for assets
22+
func New(repository, algorithm string) *Set {
23+
return &Set{
24+
Assets: []*Asset{},
25+
repository: repository,
26+
algorithm: algorithm,
27+
}
28+
}
29+
30+
// Add assets to the list
31+
func (s *Set) Add(assetConfigs ...config.Asset) error {
32+
for _, assetConfig := range assetConfigs {
33+
asset, err := NewAsset(s.repository, assetConfig, s.algorithm)
34+
if err != nil {
35+
return err
36+
}
37+
s.Assets = append(s.Assets, asset)
38+
}
39+
return nil
40+
}
41+
42+
func (s *Set) All() []*Asset {
43+
return s.Assets
44+
}
45+
46+
func (s *Set) GenerateChecksum() error {
47+
checksumFile, err := ioutil.TempFile(os.TempDir(), "checksum.*.txt")
48+
if err != nil {
49+
return errors.Wrap(err, "Could not generate tmp file for checksum")
50+
}
51+
defer checksumFile.Close()
52+
lines := []string{}
53+
for _, asset := range s.Assets {
54+
checksum, err := asset.getChecksum()
55+
if err != nil {
56+
return err
57+
}
58+
lines = append(lines, fmt.Sprintf("%s %s", checksum, asset.GetName()))
59+
}
60+
61+
w := bufio.NewWriter(checksumFile)
62+
for _, line := range lines {
63+
fmt.Fprintln(w, line)
64+
}
65+
66+
filePath, err := filepath.Abs(checksumFile.Name())
67+
if err != nil {
68+
return err
69+
}
70+
71+
s.Assets = append(s.Assets, &Asset{
72+
path: filePath,
73+
name: "checksum.txt",
74+
isCompressed: false,
75+
algorithm: "",
76+
})
77+
return w.Flush()
78+
79+
}

internal/releaser/git/git.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"time"
66

7+
"github.com/Nightapes/go-semantic-release/internal/assets"
78
"github.com/Nightapes/go-semantic-release/internal/gitutil"
89
"github.com/Nightapes/go-semantic-release/internal/shared"
910
"github.com/Nightapes/go-semantic-release/pkg/config"
@@ -64,7 +65,7 @@ func (g *Client) GetCompareURL(oldVersion, newVersion string) string {
6465
}
6566

6667
// CreateRelease creates release on remote
67-
func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog) error {
68+
func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog, _ *assets.Set) error {
6869

6970
tag := "v" + releaseVersion.Next.Version.String()
7071
g.log.Infof("create release with version %s", tag)

internal/releaser/github/github.go

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os"
88
"strings"
99

10+
"github.com/Nightapes/go-semantic-release/internal/assets"
1011
"github.com/Nightapes/go-semantic-release/internal/releaser/util"
1112
"github.com/Nightapes/go-semantic-release/internal/shared"
1213
"github.com/Nightapes/go-semantic-release/pkg/config"
@@ -78,7 +79,16 @@ func (g *Client) GetCompareURL(oldVersion, newVersion string) string {
7879
}
7980

8081
// CreateRelease creates release on remote
81-
func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog) error {
82+
func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog, assets *assets.Set) error {
83+
err := g.makeRelease(releaseVersion, generatedChangelog)
84+
if err != nil {
85+
return err
86+
}
87+
return g.uploadAssets(assets)
88+
}
89+
90+
// CreateRelease creates release on remote
91+
func (g *Client) makeRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog) error {
8292

8393
tag := "v" + releaseVersion.Next.Version.String()
8494
g.log.Debugf("create release with version %s", tag)
@@ -107,15 +117,14 @@ func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedC
107117
}
108118

109119
// UploadAssets uploads specified assets
110-
func (g *Client) UploadAssets(repoDir string, assets []config.Asset) error {
120+
func (g *Client) uploadAssets(assets *assets.Set) error {
111121
if g.release != nil {
112-
filesToUpload, err := util.PrepareAssets(repoDir, assets)
113-
if err != nil {
114-
return err
115-
}
116-
for _, f := range filesToUpload {
117-
118-
file, err := os.Open(*f)
122+
for _, asset := range assets.All() {
123+
path, err := asset.GetPath()
124+
if err != nil {
125+
return err
126+
}
127+
file, err := os.Open(path)
119128
if err != nil {
120129
return err
121130
}

internal/releaser/github/github_test.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package github_test
1+
package github
22

33
import (
44
"fmt"
@@ -11,7 +11,6 @@ import (
1111

1212
"github.com/Masterminds/semver"
1313

14-
"github.com/Nightapes/go-semantic-release/internal/releaser/github"
1514
"github.com/Nightapes/go-semantic-release/internal/shared"
1615
"github.com/Nightapes/go-semantic-release/pkg/config"
1716
"github.com/stretchr/testify/assert"
@@ -123,7 +122,7 @@ func TestNew(t *testing.T) {
123122
os.Setenv("GITHUB_TOKEN", "XXX")
124123
}
125124

126-
_, err := github.New(&testOject.config, true)
125+
_, err := New(&testOject.config, true)
127126
assert.Equal(t, testOject.valid, err == nil)
128127

129128
os.Unsetenv("GITHUB_TOKEN")
@@ -134,7 +133,7 @@ func TestNew(t *testing.T) {
134133
func TestGetCommitURL(t *testing.T) {
135134
os.Setenv("GITHUB_TOKEN", "XX")
136135
for _, testOject := range testNewClient {
137-
client, _ := github.New(&testOject.config, false)
136+
client, _ := New(&testOject.config, false)
138137
actualURL := client.GetCommitURL()
139138
if testOject.config.CustomURL != "" {
140139
expectedURL := fmt.Sprintf("%s/%s/%s/commit/{{hash}}", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo)
@@ -152,7 +151,7 @@ func TestGetCommitURL(t *testing.T) {
152151
func TestGetCompareURL(t *testing.T) {
153152
os.Setenv("GITHUB_TOKEN", "XX")
154153
for _, testOject := range testNewClient {
155-
client, _ := github.New(&testOject.config, false)
154+
client, _ := New(&testOject.config, false)
156155
actualURL := client.GetCompareURL("1", "2")
157156
if testOject.config.CustomURL != "" {
158157
expectedURL := fmt.Sprintf("%s/%s/%s/compare/%s...%s", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo, "1", "2")
@@ -174,9 +173,9 @@ func TestCreateRelease(t *testing.T) {
174173
if testObejct.valid {
175174
server := initHTTPServer(testObejct.requestResponseCode, testObejct.requestResponseBody)
176175
testObejct.config.CustomURL = server.URL
177-
client, _ := github.New(&testObejct.config, false)
176+
client, _ := New(&testObejct.config, false)
178177

179-
err := client.CreateRelease(testObejct.releaseVersion, testObejct.generatedChangelog)
178+
err := client.makeRelease(testObejct.releaseVersion, testObejct.generatedChangelog)
180179
if err != nil {
181180
t.Log(err)
182181
}
@@ -186,9 +185,9 @@ func TestCreateRelease(t *testing.T) {
186185

187186
} else {
188187
testObejct.config.CustomURL = "http://foo"
189-
client, _ := github.New(&testObejct.config, false)
188+
client, _ := New(&testObejct.config, false)
190189

191-
err := client.CreateRelease(testObejct.releaseVersion, testObejct.generatedChangelog)
190+
err := client.makeRelease(testObejct.releaseVersion, testObejct.generatedChangelog)
192191
if err != nil {
193192
t.Log(err)
194193
}

0 commit comments

Comments
 (0)