Skip to content

Commit

Permalink
fix multi-chart upload with shared version
Browse files Browse the repository at this point in the history
  • Loading branch information
pete911 committed Mar 21, 2022
1 parent 207f748 commit 5b3e950
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 58 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
fetch-depth: 0
- name: Download chart releaser
run: |
curl -sSLo hcr.tar.gz "https://github.com/pete911/hcr/releases/download/v0.0.3/hcr_0.0.3_linux_amd64.tar.gz"
curl -sSLo hcr.tar.gz "https://github.com/pete911/hcr/releases/download/v0.0.4/hcr_0.0.4_linux_amd64.tar.gz"
tar -xzf hcr.tar.gz
rm -f hcr.tar.gz
- name: Package and release chart
Expand Down
82 changes: 52 additions & 30 deletions internal/github/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,58 +32,80 @@ func NewClient(log *zap.Logger, token string) Client {
return Client{log: log, gh: github.NewClient(tc)}
}

// ReleaseExists checks if the release already exists
func (c Client) ReleaseExists(ctx context.Context, owner, repo, tag string) (bool, error) {
_, _, err := c.gh.Repositories.GetReleaseByTag(ctx, owner, repo, tag)
if err == nil {
return true, nil
// ReleaseAndAssetExists checks if the release and asset already exists
func (c Client) ReleaseAndAssetExists(ctx context.Context, owner, repo, tag, assetPath string) (bool, bool, error) {
release, _, err := c.gh.Repositories.GetReleaseByTag(ctx, owner, repo, tag)
if err != nil {
// release does not exist (no assets)
if ghError, ok := err.(*github.ErrorResponse); ok && ghError.Response.StatusCode == http.StatusNotFound {
return false, false, nil
}
}

if ghError, ok := err.(*github.ErrorResponse); ok {
if ghError.Response.StatusCode == http.StatusNotFound {
return false, nil
for _, asset := range release.Assets {
if asset == nil {
continue
}
if asset.GetName() == assetPath {
return true, true, nil
}
}
return false, err
return true, false, err
}

// CreateRelease creates release and returns asset url
func (c Client) CreateRelease(ctx context.Context, owner, repo, tag string, release Release) (string, error) {
// CreateRelease creates release (if it doesn't exist) and returns release id
func (c Client) CreateRelease(ctx context.Context, release Release, dryRun bool) (int64, error) {
existingRelease, _, err := c.gh.Repositories.GetReleaseByTag(ctx, release.Owner, release.Repo, release.Tag)
if err == nil {
c.log.Info(fmt.Sprintf("%s release %s already exists, skipping create release", release.Name, release.Tag))
return existingRelease.GetID(), nil
}
if err != nil {
// not a gitHub error and not 404
if ghError, ok := err.(*github.ErrorResponse); !ok || ghError.Response.StatusCode != http.StatusNotFound {
return 0, fmt.Errorf("get release by %s tag: %w", release.Tag, err)
}
}
if dryRun {
c.log.Info(fmt.Sprintf("%s create release %s skipping, dry run is set to true", release.Name, release.Tag))
return 0, nil
}

request := &github.RepositoryRelease{
Name: &release.Name,
Body: &release.Description,
TagName: &tag,
TagName: &release.Tag,
Prerelease: &release.PreRelease,
}

response, _, err := c.gh.Repositories.CreateRelease(ctx, owner, repo, request)
response, _, err := c.gh.Repositories.CreateRelease(ctx, release.Owner, release.Repo, request)
if err != nil {
return "", err
return 0, fmt.Errorf("%s create release %s: %w", release.Name, release.Tag, err)
}
c.log.Info(fmt.Sprintf("release %s created", release.Name))
c.log.Info(fmt.Sprintf("%s release %s with id %d created", release.Name, release.Tag, response.GetID()))
return response.GetID(), nil
}

// upload assets
url, err := c.uploadAsset(ctx, owner, repo, *response.ID, release.AssetPath)
// UploadAsset upload asset and return asset download url
func (c Client) UploadAsset(ctx context.Context, releaseId int64, release Release) (string, error) {
existingRelease, _, err := c.gh.Repositories.GetRelease(ctx, release.Owner, release.Repo, releaseId)
if err != nil {
return "", fmt.Errorf("upload release asset %s: %w", release.AssetPath, err)
return "", fmt.Errorf("get release by %d id: %w", releaseId, err)
}
for _, asset := range existingRelease.Assets {
if asset != nil && asset.GetName() == release.AssetPath {
c.log.Info(fmt.Sprintf("%s release %s asset %s already exists, skipping create asset", release.Name, release.Tag, asset.GetBrowserDownloadURL()))
return asset.GetBrowserDownloadURL(), nil
}
}
c.log.Info(fmt.Sprintf("asset %s uploaded", release.AssetPath))
return url, nil
}

func (c Client) uploadAsset(ctx context.Context, owner, repo string, id int64, assetPath string) (string, error) {
f, err := os.Open(assetPath)
f, err := os.Open(release.AssetPath)
if err != nil {
return "", err
}
defer func() {
if err := f.Close(); err != nil {
c.log.Warn(fmt.Sprintf("close %s asset file: %v", assetPath, err))
}
}()
defer f.Close()

opts := &github.UploadOptions{Name: assetPath}
asset, _, err := c.gh.Repositories.UploadReleaseAsset(ctx, owner, repo, id, opts, f)
opts := &github.UploadOptions{Name: release.AssetPath}
asset, _, err := c.gh.Repositories.UploadReleaseAsset(ctx, release.Owner, release.Repo, releaseId, opts, f)
return asset.GetBrowserDownloadURL(), err
}
4 changes: 4 additions & 0 deletions internal/github/release.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package github

type Release struct {
Owner string
Repo string
Tag string

Name string
Description string
AssetPath string
Expand Down
33 changes: 16 additions & 17 deletions internal/hcr/releaser.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,33 +106,32 @@ func (r Releaser) releaseChartAndUpdateIndex(ctx context.Context, chartPath stri
return false, fmt.Errorf("get github owner and repo: %w", err)
}

tag := r.GetReleaseTag(ch)
ok, err := r.ghClient.ReleaseExists(ctx, owner, repo, tag)
if err != nil {
return false, fmt.Errorf("%s release %s exists: %w", ch.Name(), tag, err)
release := github.Release{
Owner: owner,
Repo: repo,
Tag: r.GetReleaseTag(ch),
Name: fmt.Sprintf("%s-%s", ch.Name(), ch.Metadata.Version),
Description: fmt.Sprintf("Kubernetes %s Helm chart", ch.Name()),
AssetPath: chartPath,
PreRelease: r.config.PreRelease,
}
if ok {
r.log.Info(fmt.Sprintf("%s release %s already exists, skipping", ch.Name(), tag))
return false, nil
releaseId, err := r.ghClient.CreateRelease(ctx, release, r.config.DryRun)
if err != nil {
return false, err
}
// releaseId is set to 0 if dry run is set to true, upload asset would fail to get release and verify assets
if r.config.DryRun {
r.log.Info(fmt.Sprintf("%s release %s skipping, dry-run set to true", ch.Name(), tag))
r.log.Info(fmt.Sprintf("%s release %s upload asset skipping, dry run is set to true", release.Name, release.Tag))
r.log.Info(fmt.Sprintf("update %s index skipping, dry-run set to true", r.ghPagesIndexPath))
return false, nil
}

release := github.Release{
Name: fmt.Sprintf("%s-%s", ch.Name(), ch.Metadata.Version),
Description: fmt.Sprintf("Kubernetes %s Helm chart", ch.Name()),
AssetPath: chartPath,
PreRelease: r.config.PreRelease,
}
assetUrl, err := r.ghClient.CreateRelease(ctx, owner, repo, tag, release)
assetUrl, err := r.ghClient.UploadAsset(ctx, releaseId, release)
if err != nil {
return false, fmt.Errorf("create %s release: %w", tag, err)
return false, err
}

ok, err = r.helmClient.UpdateIndex(r.ghPagesIndexPath, chartPath, ch, assetUrl)
ok, err := r.helmClient.UpdateIndex(r.ghPagesIndexPath, chartPath, ch, assetUrl)
if err != nil {
return false, fmt.Errorf("update %s index file: %w", r.ghPagesIndexPath, err)
}
Expand Down
18 changes: 9 additions & 9 deletions internal/helm/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,20 @@ func (c Client) PackageCharts(chartsDir string) (charts map[string]*chart.Chart,
}

// PackageChart package given chart in current working directory (<name>-<version>.tgz) and return packaged chart
// location and metadata
func (c Client) PackageChart(path string) (string, *chart.Chart, error) {
c.log.Info(fmt.Sprintf("start package %s chart", path))
packagedChart, err := c.pkg.Run(path, nil)
// path and metadata
func (c Client) PackageChart(chartPath string) (string, *chart.Chart, error) {
c.log.Info(fmt.Sprintf("start package %s chart", chartPath))
packagedChartPath, err := c.pkg.Run(chartPath, nil)
if err != nil {
return "", nil, fmt.Errorf("package chart at %s path: %w", path, err)
return "", nil, fmt.Errorf("package chart at %s path: %w", chartPath, err)
}
c.log.Info(fmt.Sprintf("chart %s packaged as %s", path, packagedChart))
ch, err := loader.LoadFile(packagedChart)
c.log.Info(fmt.Sprintf("chart %s packaged as %s", chartPath, packagedChartPath))
ch, err := loader.LoadFile(packagedChartPath)
if err != nil {
return "", nil, fmt.Errorf("load chart: %w", err)
}
c.log.Info(fmt.Sprintf("chart %s loaded", ch.Name()))
return packagedChart, ch, nil
return packagedChartPath, ch, nil
}

// UpdateIndex at the specified location with given chart. Base URL is url without chart name.
Expand All @@ -100,7 +100,7 @@ func (c Client) UpdateIndex(indexFilePath, archiveChartPath string, chart *chart

// chart already exists in the index
if _, err := indexFile.Get(chart.Name(), chart.Metadata.Version); err == nil {
c.log.Info(fmt.Sprintf("index file get %s %s: %v", chart.Name(), chart.Metadata.Version, err))
c.log.Info(fmt.Sprintf("chart %s %s already exists in the helm index", chart.Name(), chart.Metadata.Version))
return false, nil
}

Expand Down
4 changes: 3 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,7 @@ func main() {
log.Error(fmt.Sprintf("marshal released charts info: %v", err))
return
}
fmt.Println(string(b))
if b != nil {
fmt.Println(string(b))
}
}

0 comments on commit 5b3e950

Please sign in to comment.