Skip to content

Commit aac7d4f

Browse files
committed
feat(cloud): Add intermediate github deployer
Signed-off-by: Cezar Craciunoiu <[email protected]>
1 parent 07661b8 commit aac7d4f

File tree

4 files changed

+210
-0
lines changed

4 files changed

+210
-0
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ require (
4040
github.com/gobwas/glob v0.2.3
4141
github.com/google/go-containerregistry v0.20.3
4242
github.com/google/go-github/v32 v32.1.0
43+
github.com/google/go-github/v39 v39.2.0
4344
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
4445
github.com/google/uuid v1.6.0
4546
github.com/henvic/httpretty v0.1.4

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,8 @@ github.com/google/go-containerregistry v0.20.3 h1:oNx7IdTI936V8CQRveCjaxOiegWwvM
674674
github.com/google/go-containerregistry v0.20.3/go.mod h1:w00pIgBRDVUDFM6bq+Qx8lwNWK+cxgCuX1vd3PIBDNI=
675675
github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II=
676676
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
677+
github.com/google/go-github/v39 v39.2.0 h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvto3aSnQ=
678+
github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE=
677679
github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM=
678680
github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y=
679681
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
@@ -1351,6 +1353,7 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh
13511353
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
13521354
golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
13531355
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
1356+
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
13541357
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
13551358
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
13561359
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
@@ -1668,6 +1671,7 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
16681671
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
16691672
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
16701673
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
1674+
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
16711675
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
16721676
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
16731677
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=

internal/cli/kraft/cloud/deploy/deployer.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type deployer interface {
4040
func deployers() []deployer {
4141
return []deployer{
4242
&deployerImageName{},
43+
&deployerKraftfileRepo{},
4344
&deployerKraftfileRuntime{},
4445
&deployerKraftfileUnikraft{},
4546
&deployerRootfs{},
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
package deploy
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"path/filepath"
7+
"sort"
8+
"strings"
9+
10+
"github.com/google/go-github/v39/github"
11+
"golang.org/x/oauth2"
12+
13+
"kraftkit.sh/config"
14+
"kraftkit.sh/internal/ghrepo"
15+
"kraftkit.sh/manifest"
16+
"kraftkit.sh/pack"
17+
kcclient "sdk.kraft.cloud/client"
18+
kcinstances "sdk.kraft.cloud/instances"
19+
kcservices "sdk.kraft.cloud/services"
20+
)
21+
22+
const treeSeparator = "/tree/"
23+
24+
type deployerKraftfileRepo struct {
25+
args []string
26+
url string
27+
}
28+
29+
func (d *deployerKraftfileRepo) Name() string {
30+
return "kraftfile-repo"
31+
}
32+
33+
func (d *deployerKraftfileRepo) String() string {
34+
if len(d.args) == 0 {
35+
return "run the given link with a Kraftfile"
36+
}
37+
38+
return fmt.Sprintf("run the detected Kraftfile in the given link after cloning and use '%s' as arg(s)", strings.Join(d.args, " "))
39+
}
40+
41+
func (d *deployerKraftfileRepo) Deployable(ctx context.Context, opts *DeployOptions, args ...string) (bool, error) {
42+
url := args[0]
43+
44+
if !strings.Contains(url, "github.com") {
45+
return false, nil
46+
}
47+
48+
if strings.Contains(url, treeSeparator) {
49+
url = strings.Split(url, treeSeparator)[0]
50+
}
51+
52+
_, err := ghrepo.NewFromURL(url)
53+
if err != nil {
54+
return false, err
55+
}
56+
57+
d.url = args[0]
58+
d.args = args[1:]
59+
60+
return true, nil
61+
}
62+
63+
// getAllBranchesSorted returns all branches of a given repository sorted
64+
// by size in descending order.
65+
// If no token is specified, it will only have access to public repositories
66+
func getAllBranchesSorted(ctx context.Context, owner, repo, token string) ([]string, error) {
67+
ts := oauth2.StaticTokenSource(
68+
&oauth2.Token{AccessToken: token},
69+
)
70+
tc := oauth2.NewClient(ctx, ts)
71+
72+
client := github.NewClient(tc)
73+
74+
var allBranches []*github.Branch
75+
opt := &github.BranchListOptions{ListOptions: github.ListOptions{PerPage: 100}}
76+
for {
77+
branches, resp, err := client.Repositories.ListBranches(ctx, owner, repo, opt)
78+
if err != nil {
79+
return nil, err
80+
}
81+
allBranches = append(allBranches, branches...)
82+
if resp.NextPage == 0 {
83+
break
84+
}
85+
opt.Page = resp.NextPage
86+
}
87+
88+
var branchNames []string
89+
for _, branch := range allBranches {
90+
branchNames = append(branchNames, branch.GetName())
91+
}
92+
93+
// Sort all branches names by size in descending order
94+
// This is done to ensure that the longest name is the first one
95+
sort.Slice(branchNames, func(i, j int) bool {
96+
return len(branchNames[i]) > len(branchNames[j])
97+
})
98+
99+
return branchNames, nil
100+
}
101+
102+
func (d *deployerKraftfileRepo) Deploy(ctx context.Context, opts *DeployOptions, _ ...string) (*kcclient.ServiceResponse[kcinstances.GetResponseItem], *kcclient.ServiceResponse[kcservices.GetResponseItem], error) {
103+
var err error
104+
var ghProvider manifest.Provider
105+
106+
link := d.url
107+
branch := ""
108+
path := "."
109+
110+
if strings.Contains(d.url, treeSeparator) {
111+
split1 := strings.SplitN(d.url, treeSeparator, 2)
112+
link = split1[0]
113+
}
114+
115+
repo, err := ghrepo.NewFromURL(link)
116+
if err != nil {
117+
return nil, nil, err
118+
}
119+
120+
if strings.Contains(d.url, treeSeparator) {
121+
branchPath := strings.SplitN(d.url, treeSeparator, 2)[1]
122+
123+
token := ""
124+
for key, auth := range config.G[config.KraftKit](ctx).Auth {
125+
if auth.Endpoint == "github.com" || key == "github.com" {
126+
token = auth.Token
127+
break
128+
}
129+
}
130+
branches, err := getAllBranchesSorted(ctx, repo.RepoOwner(), repo.RepoName(), token)
131+
if err != nil {
132+
return nil, nil, err
133+
}
134+
135+
for _, branchName := range branches {
136+
if strings.HasPrefix(branchPath, branchName) {
137+
branch = branchName
138+
break
139+
}
140+
}
141+
142+
if branch == "" {
143+
return nil, nil, fmt.Errorf("could not match branch from given url, are you sure the url is correct?")
144+
}
145+
146+
path = strings.SplitN(branchPath, branch+"/", 2)[1]
147+
}
148+
149+
ghProvider, err = manifest.NewGitHubProvider(
150+
ctx,
151+
link,
152+
manifest.WithAuthConfig(config.G[config.KraftKit](ctx).Auth),
153+
manifest.WithUpdate(true))
154+
if err != nil {
155+
return nil, nil, err
156+
}
157+
158+
var m *manifest.Manifest = &manifest.Manifest{
159+
Type: "app",
160+
Name: repo.RepoName(),
161+
Origin: link,
162+
Provider: ghProvider,
163+
Channels: []manifest.ManifestChannel{
164+
{
165+
Name: branch,
166+
Default: true,
167+
Resource: link,
168+
},
169+
},
170+
}
171+
172+
p, err := manifest.NewPackageFromManifest(
173+
m,
174+
manifest.WithAuthConfig(config.G[config.KraftKit](ctx).Auth),
175+
manifest.WithUpdate(true),
176+
)
177+
if err != nil {
178+
return nil, nil, err
179+
}
180+
181+
err = p.Pull(
182+
ctx,
183+
pack.WithPullWorkdir(opts.Workdir),
184+
pack.WithPullUnstructured(true),
185+
)
186+
if err != nil {
187+
return nil, nil, err
188+
}
189+
190+
opts.Workdir = filepath.Join(opts.Workdir, repo.RepoName(), path)
191+
192+
deployers := []deployer{
193+
&deployerKraftfileRuntime{},
194+
&deployerKraftfileUnikraft{},
195+
}
196+
197+
for _, deployer := range deployers {
198+
if deployable, _ := deployer.Deployable(ctx, opts, d.args...); deployable {
199+
return deployer.Deploy(ctx, opts, d.args...)
200+
}
201+
}
202+
203+
return nil, nil, fmt.Errorf("no deployer found for the given project link")
204+
}

0 commit comments

Comments
 (0)