Skip to content

Commit

Permalink
✨ Implement publish command (#146)
Browse files Browse the repository at this point in the history
* ✨ Implement publish command

`csmctl publish` will generate the release similar to create command but
additionally it will push the generated release to the oci repository.

For this, we implemented the generic interface for assetsclients that we
have in the CSO as well and that is fulfilled both by Github and OCI
clients.

Signed-off-by: janiskemper <[email protected]>

* Add basic auth option for the oci client (#148)

Signed-off-by: Roman Hros <[email protected]>

---------

Signed-off-by: janiskemper <[email protected]>
Signed-off-by: Roman Hros <[email protected]>
Co-authored-by: Roman Hros <[email protected]>
  • Loading branch information
janiskemper and chess-knight authored Aug 27, 2024
1 parent be4643f commit a743d0c
Show file tree
Hide file tree
Showing 82 changed files with 11,095 additions and 121 deletions.
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ go 1.21
require (
github.com/SovereignCloudStack/cluster-stack-operator v0.1.0-alpha.5
github.com/google/go-github/v56 v56.0.0
github.com/opencontainers/image-spec v1.1.0
github.com/spf13/cobra v1.8.0
github.com/valyala/fasttemplate v1.2.2
golang.org/x/mod v0.16.0
golang.org/x/oauth2 v0.18.0
gopkg.in/src-d/go-git.v4 v4.13.1
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
helm.sh/helm/v3 v3.14.4
oras.land/oras-go/v2 v2.5.0
)

require (
Expand Down Expand Up @@ -100,7 +103,6 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.17.0 // indirect
Expand Down Expand Up @@ -128,7 +130,7 @@ require (
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
Expand All @@ -140,7 +142,6 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/api v0.29.0 // indirect
k8s.io/apiextensions-apiserver v0.29.0 // indirect
k8s.io/apimachinery v0.29.0 // indirect
Expand Down
10 changes: 6 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,8 @@ github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
Expand Down Expand Up @@ -488,8 +488,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down Expand Up @@ -627,6 +627,8 @@ k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSn
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY=
oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324=
oras.land/oras-go/v2 v2.5.0 h1:o8Me9kLY74Vp5uw07QXPiitjsw7qNXi8Twd+19Zf02c=
oras.land/oras-go/v2 v2.5.0/go.mod h1:z4eisnLP530vwIOUOJeBIj0aGI0L1C3d53atvCBqZHg=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0=
Expand Down
44 changes: 44 additions & 0 deletions pkg/assetsclient/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
Copyright 2024 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package assetsclient contains interface for talking to assets repositories.
package assetsclient

import (
"context"
)

// Client contains functions to talk to list and download assets.
type Client interface {
DownloadReleaseAssets(ctx context.Context, tag, path string) error
ListRelease(ctx context.Context) ([]string, error)
}

// Factory is a factory to generate assets clients.
type Factory interface {
NewClient(ctx context.Context) (Client, error)
}

// Pusher contains function to push the release assets to the registry.
type Pusher interface {
PushReleaseAssets(ctx context.Context, releaseAssets []ReleaseAsset, tag, dir, artifactType string, metadata map[string]string) error
}

// ReleaseAsset represents a release asset that would together make up the artifact.
type ReleaseAsset struct {
FileName string
MediaType string
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package client
// Package github provides utilities to work with github repostories.
package github

import (
"context"
Expand All @@ -23,24 +24,12 @@ import (
"net/http"
"os"
"path/filepath"
"strings"

"github.com/SovereignCloudStack/csctl/pkg/assetsclient"
"github.com/google/go-github/v56/github"
"golang.org/x/oauth2"
)

// Client contains all functions to talk to Github API.
type Client interface {
DownloadReleaseAssets(ctx context.Context, release *github.RepositoryRelease, path string, assetlist []string) error
GetReleaseByTag(ctx context.Context, tag string) (*github.RepositoryRelease, *github.Response, error)
ListRelease(ctx context.Context) ([]*github.RepositoryRelease, *github.Response, error)
}

// Factory is a factory to generate Github clients.
type Factory interface {
NewClient(ctx context.Context) (Client, error)
}

type realGhClient struct {
client *github.Client
httpclient *http.Client
Expand All @@ -50,18 +39,18 @@ type realGhClient struct {

type factory struct{}

var _ = Client(&realGhClient{})
var _ = assetsclient.Client(&realGhClient{})

var _ = Factory(&factory{})
var _ = assetsclient.Factory(&factory{})

// NewFactory returns a new factory for Github clients.
func NewFactory() Factory {
func NewFactory() assetsclient.Factory {
return &factory{}
}

var _ = Client(&realGhClient{})
var _ = assetsclient.Client(&realGhClient{})

func (*factory) NewClient(ctx context.Context) (Client, error) {
func (*factory) NewClient(ctx context.Context) (assetsclient.Client, error) {
creds, err := NewGitConfig()
if err != nil {
return nil, fmt.Errorf("failed to create git config: %w", err)
Expand All @@ -83,16 +72,26 @@ func (*factory) NewClient(ctx context.Context) (Client, error) {
}, nil
}

func (c *realGhClient) ListRelease(ctx context.Context) ([]*github.RepositoryRelease, *github.Response, error) {
func (c *realGhClient) ListRelease(ctx context.Context) ([]string, error) {
repoRelease, response, err := c.client.Repositories.ListReleases(ctx, c.orgName, c.repoName, &github.ListOptions{})
if err != nil {
return nil, nil, fmt.Errorf("failed to list releases: %w", err)
return nil, fmt.Errorf("failed to list releases: %w", err)
}

return repoRelease, response, nil
if response != nil && response.StatusCode != 200 {
return nil, fmt.Errorf("got unexpected status from call to remote repository: %s", response.Status)
}

releases := []string{}

for _, release := range repoRelease {
releases = append(releases, *release.Name)
}

return releases, nil
}

func (c *realGhClient) GetReleaseByTag(ctx context.Context, tag string) (*github.RepositoryRelease, *github.Response, error) {
func (c *realGhClient) getReleaseByTag(ctx context.Context, tag string) (*github.RepositoryRelease, *github.Response, error) {
repoRelease, response, err := c.client.Repositories.GetReleaseByTag(ctx, c.orgName, c.repoName, tag)
if err != nil {
return nil, nil, fmt.Errorf("failed to get release tag: %w", err)
Expand All @@ -102,15 +101,21 @@ func (c *realGhClient) GetReleaseByTag(ctx context.Context, tag string) (*github
}

// DownloadReleaseAssets downloads a list of release assets.
func (c *realGhClient) DownloadReleaseAssets(ctx context.Context, release *github.RepositoryRelease, path string, assetlist []string) error {
func (c *realGhClient) DownloadReleaseAssets(ctx context.Context, tag, path string) error {
release, response, err := c.getReleaseByTag(ctx, tag)
if err != nil {
return fmt.Errorf("failed to fetch release tag %s: %w", tag, err)
}

if response.StatusCode != http.StatusOK {
return fmt.Errorf("failed to fetch release tag %s with status code %d: %w", tag, response.StatusCode, err)
}

if err := os.MkdirAll(path, os.ModePerm); err != nil {
return fmt.Errorf("failed to create destination directory: %w", err)
}
// Extract the release assets
for _, asset := range release.Assets {
if !contains(assetlist, asset.GetName()) {
continue
}
assetPath := filepath.Join(path, asset.GetName())
// Create a temporary file (inside the dest dir) to save the downloaded asset file
assetFile, err := os.Create(filepath.Clean(assetPath))
Expand Down Expand Up @@ -200,12 +205,3 @@ func verifyAccess(ctx context.Context, client *github.Client, creds GitConfig) e
}
return nil
}

func contains(source []string, ghAsset string) bool {
for _, a := range source {
if a == ghAsset || strings.Contains(ghAsset, a) {
return true
}
}
return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

// Package client implements important functions for github client.
package client
package github

import (
"fmt"
Expand Down
Loading

0 comments on commit a743d0c

Please sign in to comment.