Skip to content

Commit

Permalink
Separate repo.Repo to registory.Registory and storage.Storage
Browse files Browse the repository at this point in the history
  • Loading branch information
k1LoW committed Oct 5, 2023
1 parent 3d107f0 commit 084ca95
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 84 deletions.
42 changes: 27 additions & 15 deletions dewy.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import (
starter "github.com/lestrrat-go/server-starter"
"github.com/linyows/dewy/kvs"
"github.com/linyows/dewy/notice"
"github.com/linyows/dewy/registory"
"github.com/linyows/dewy/repo"
"github.com/linyows/dewy/storage"
)

const (
Expand All @@ -30,7 +32,8 @@ const (
// Dewy struct
type Dewy struct {
config Config
repo repo.Repo
registory registory.Registory
fetcher storage.Fetcher
cache kvs.KVS
isServerRunning bool
root string
Expand All @@ -57,7 +60,8 @@ func New(c Config) (*Dewy, error) {
return &Dewy{
config: c,
cache: kv,
repo: r,
registory: r,
fetcher: r,
isServerRunning: false,
root: wd,
}, nil
Expand All @@ -69,15 +73,20 @@ func (d *Dewy) Start(i int) {
defer cancel()
var err error

d.notice, err = notice.New(&notice.Slack{Meta: &notice.Config{
RepoOwnerLink: d.repo.OwnerURL(),
RepoOwnerIcon: d.repo.OwnerIconURL(),
RepoLink: d.repo.URL(),
RepoOwner: d.config.Repository.Owner,
RepoName: d.config.Repository.Name,
Source: d.config.Repository.Artifact,
Command: d.config.Command.String(),
}})
nc := &notice.Config{
RepoOwner: d.config.Repository.Owner,
RepoName: d.config.Repository.Name,
Source: d.config.Repository.Artifact,
Command: d.config.Command.String(),
}
repo, ok := d.registory.(repo.Repo)
if ok {
nc.RepoOwnerLink = repo.OwnerURL()
nc.RepoOwnerIcon = repo.OwnerIconURL()
nc.RepoLink = repo.URL()
}

d.notice, err = notice.New(&notice.Slack{Meta: nc})
if err != nil {
log.Printf("[ERROR] Notice failure: %#v", err)
return
Expand Down Expand Up @@ -114,7 +123,7 @@ func (d *Dewy) Run() error {
defer cancel()

// Get current
res, err := d.repo.Current(&repo.CurrentRequest{
res, err := d.registory.Current(&registory.CurrentRequest{
ArtifactName: d.config.Repository.Artifact,
})
if err != nil {
Expand Down Expand Up @@ -148,7 +157,7 @@ func (d *Dewy) Run() error {
// Download artifact and cache
if !found {
buf := new(bytes.Buffer)
if err := d.repo.Download(buf); err != nil {
if err := d.fetcher.Fetch(res.ArtifactURL, buf); err != nil {
return err
}
if err := d.cache.Write(cacheKey, buf.Bytes()); err != nil {
Expand All @@ -159,7 +168,7 @@ func (d *Dewy) Run() error {

if d.notice != nil {
d.notice.Notify(ctx, fmt.Sprintf("New shipping <%s|%s> was detected",
d.repo.ReleaseURL(), d.repo.ReleaseTag()))
res.ArtifactURL, res.Tag))
}

if err := d.deploy(cacheKey); err != nil {
Expand All @@ -180,7 +189,10 @@ func (d *Dewy) Run() error {
}

log.Print("[DEBUG] Record shipping")
err = d.repo.RecordShipping()
err = d.registory.Report(&registory.ReportRequest{
ID: res.ID,
Tag: res.Tag,
})
if err != nil {
log.Printf("[ERROR] Record shipping failure: %#v", err)
}
Expand Down
3 changes: 2 additions & 1 deletion dewy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ func TestNew(t *testing.T) {
}
expect := &Dewy{
config: c,
repo: r,
registory: r,
fetcher: r,
cache: dewy.cache,
isServerRunning: false,
root: wd,
Expand Down
36 changes: 36 additions & 0 deletions registory/registory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package registory

type Registory interface {
// Current returns the current artifact.
Current(*CurrentRequest) (*CurrentResponse, error)
// Report reports the result of deploying the artifact.
Report(*ReportRequest) error
}

// CurrentRequest is the request to get the current artifact.
type CurrentRequest struct {
// ArtifactName is the name of the artifact to fetch.
// FIXME: If possible, ArtifactName should be optional.
ArtifactName string
}

// CurrentResponse is the response to get the current artifact.
type CurrentResponse struct {
// ID uniquely identifies the response.
ID string
// Tag uniquely identifies the artifact concerned.
Tag string
// ArtifactURL is the URL to download the artifact.
// The URL is not only "https://"
ArtifactURL string
}

// ReportRequest is the request to report the result of deploying the artifact.
type ReportRequest struct {
// ID is the ID of the response.
ID string
// Tag is the current tag of deployed artifact.
Tag string
// Err is the error that occurred during deployment. If Err is nil, the deployment is considered successful.
Err error
}
143 changes: 97 additions & 46 deletions repo/github_release.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import (
"github.com/google/go-github/v55/github"
"github.com/google/go-querystring/query"
"github.com/k1LoW/go-github-client/v55/factory"
"github.com/linyows/dewy/registory"
)

const (
GitHubReleaseScheme = "github_release"
// ISO8601 for time format

Check failure on line 23 in repo/github_release.go

View workflow job for this annotation

GitHub Actions / GolongCI Lint

Comment should end in a period (godot)
ISO8601 = "20060102T150405Z0700"
)
Expand All @@ -26,18 +28,15 @@ var httpClient = &http.Client{
Timeout: 30 * time.Second,
}

var _ Repo = (*GithubRelease)(nil)

// GithubRelease struct

Check failure on line 33 in repo/github_release.go

View workflow job for this annotation

GitHub Actions / GolongCI Lint

Comment should end in a period (godot)
type GithubRelease struct {
baseURL string
uploadURL string
owner string
name string
artifact string
downloadURL string
releaseID int64
assetID int64
releaseURL string
releaseTag string
prerelease bool
disableRecordShipping bool // FIXME: For testing. Remove this.
cl *github.Client
Expand All @@ -53,7 +52,6 @@ func NewGithubRelease(c Config) (*GithubRelease, error) {
g := &GithubRelease{
owner: c.Owner,
name: c.Name,
artifact: c.Artifact,
prerelease: c.PreRelease,
disableRecordShipping: c.DisableRecordShipping,
cl: cl,
Expand Down Expand Up @@ -92,33 +90,19 @@ func (g *GithubRelease) URL() string {
return fmt.Sprintf("%s/%s", g.OwnerURL(), g.name)
}

// ReleaseTag returns tag
func (g *GithubRelease) ReleaseTag() string {
return g.releaseTag
}

// ReleaseURL returns release URL
func (g *GithubRelease) ReleaseURL() string {
return g.releaseURL
}

func (g *GithubRelease) Current(req *CurrentRequest) (*CurrentResponse, error) {
func (g *GithubRelease) Current(req *registory.CurrentRequest) (*registory.CurrentResponse, error) {
release, err := g.latest()
if err != nil {
return nil, err
}

g.releaseID = *release.ID
g.releaseURL = *release.HTMLURL

found := false
for _, v := range release.Assets {
if v.GetName() == req.ArtifactName {
found = true
log.Printf("[DEBUG] Fetched: %+v", v)
g.downloadURL = v.GetBrowserDownloadURL()
g.releaseTag = release.GetTagName()
g.assetID = v.GetID()
g.updatedAt = v.GetUpdatedAt()
break
}
Expand All @@ -129,7 +113,8 @@ func (g *GithubRelease) Current(req *CurrentRequest) (*CurrentResponse, error) {

au := fmt.Sprintf("github_release://%s/%s/tag/%s/%s", g.owner, g.name, release.GetTagName(), req.ArtifactName)

return &CurrentResponse{
return &registory.CurrentResponse{
ID: time.Now().Format(ISO8601),
Tag: release.GetTagName(),
ArtifactURL: au,
}, nil
Expand Down Expand Up @@ -158,9 +143,53 @@ func (g *GithubRelease) latest() (*github.RepositoryRelease, error) {
return r, nil
}

func (g *GithubRelease) Download(w io.Writer) error {
func (g *GithubRelease) Fetch(url string, w io.Writer) error {
ctx := context.Background()
reader, url, err := g.cl.Repositories.DownloadReleaseAsset(ctx, g.owner, g.name, g.assetID, httpClient)
// github_release://owner/repo/tag/v1.0.0/artifact.zip
// github_release://owner/repo/latest/artifact.zip
splitted := strings.Split(strings.TrimPrefix(url, fmt.Sprintf("%s://", GitHubReleaseScheme)), "/")
if len(splitted) != 4 && len(splitted) != 5 {
return fmt.Errorf("invalid url: %s", url)
}
owner := splitted[0]
name := splitted[1]
if len(splitted) == 4 {
// latest
// FIXME: not implemented
return fmt.Errorf("not implemented")
}
tag := splitted[3]
artifactName := splitted[4]
page := 1
var assetID int64
L:
for {
releases, res, err := g.cl.Repositories.ListReleases(ctx, g.owner, g.name, &github.ListOptions{
Page: page,
PerPage: 100,
})
if err != nil {
return err
}
for _, r := range releases {
if r.GetTagName() != tag {
continue
}
for _, a := range r.Assets {
if a.GetName() != artifactName {
continue
}
assetID = a.GetID()
break L
}
}
if res.NextPage == 0 {
break
}
page = res.NextPage
}

reader, url, err := g.cl.Repositories.DownloadReleaseAsset(ctx, owner, name, assetID, httpClient)
if err != nil {
return err
}
Expand All @@ -181,38 +210,60 @@ func (g *GithubRelease) Download(w io.Writer) error {
return nil
}

// RecordShipping save shipping to github
func (g *GithubRelease) RecordShipping() error {
func (g *GithubRelease) Report(req *registory.ReportRequest) error {
if g.disableRecordShipping {
return nil
}
if req.Err != nil {
return req.Err
}
ctx := context.Background()
now := time.Now().UTC().Format(ISO8601)
hostname, _ := os.Hostname()
info := fmt.Sprintf("shipped to %s at %s", strings.ToLower(hostname), now)

s := fmt.Sprintf("repos/%s/%s/releases/%d/assets", g.owner, g.name, g.releaseID)
opt := &github.UploadOptions{Name: strings.Replace(info, " ", "_", -1) + ".txt"}
page := 1
for {
releases, res, err := g.cl.Repositories.ListReleases(ctx, g.owner, g.name, &github.ListOptions{
Page: page,
PerPage: 100,
})
if err != nil {
return err
}
for _, r := range releases {
if r.GetTagName() == req.Tag {
s := fmt.Sprintf("repos/%s/%s/releases/%d/assets", g.owner, g.name, r.GetID())
opt := &github.UploadOptions{Name: strings.Replace(info, " ", "_", -1) + ".txt"}

u, err := url.Parse(s)
if err != nil {
return err
}
qs, err := query.Values(opt)
if err != nil {
return err
}
u.RawQuery = qs.Encode()
u, err := url.Parse(s)
if err != nil {
return err
}
qs, err := query.Values(opt)
if err != nil {
return err
}
u.RawQuery = qs.Encode()
b := []byte(info)
r := bytes.NewReader(b)
req, err := g.cl.NewUploadRequest(u.String(), r, int64(len(b)), "text/plain")
if err != nil {
return err
}

byteData := []byte(info)
r := bytes.NewReader(byteData)
req, err := g.cl.NewUploadRequest(u.String(), r, int64(len(byteData)), "text/plain")
if err != nil {
return err
asset := new(github.ReleaseAsset)
if _, err := g.cl.Do(ctx, req, asset); err != nil {
return err
}
return nil
}
}
if res.NextPage == 0 {
break
}
page = res.NextPage
}

asset := new(github.ReleaseAsset)
_, err = g.cl.Do(ctx, req, asset)

return err
return fmt.Errorf("release not found: %s", req.Tag)
}
Loading

0 comments on commit 084ca95

Please sign in to comment.