Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ release:
GOOS=windows GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_windows_amd64

install: build
mkdir -p ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH}
mv ${BINARY} ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH}
mkdir -p ~/.terraform.d/plugins/local/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH}
mv ${BINARY} ~/.terraform.d/plugins/local/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH}

test:
go test -i $(TEST) || exit 1
Expand Down
40 changes: 27 additions & 13 deletions pkg/application/creation.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,16 @@ type Deployment struct {
PrivateSSHKey *string
}

func (d Deployment) GetCommit() string {
if d.Commit != nil {
return *d.Commit
}
return "<nil>"
}

type CreateRes struct {
Application tmp.CreatAppResponse
Commit string // when there is a git URL to deploy but no commit SET
}

func (r *CreateRes) GetBuildFlavor() types.String {
Expand Down Expand Up @@ -92,18 +100,13 @@ func CreateApp(ctx context.Context, req CreateReq) (*CreateRes, diag.Diagnostics
}
res.Application.Vhosts = *vhostsRes.Payload()

// Git Deployment
if req.Deployment != nil {
diags.Append(gitDeploy(ctx, *req.Deployment, req.Client, res.Application.DeployURL)...)
}

// Dependencies
dependenciesWithAddonIDs, err := tmp.RealIDsToAddonIDs(ctx, req.Client, req.Organization, req.Dependencies...)
if err != nil {
diags.AddError("failed to get dependencies addon IDs", err.Error())
return nil, diags
}
tflog.Debug(ctx, "[create] dependencies to link", map[string]any{"dependencies": req.Dependencies, "addonIds": dependenciesWithAddonIDs})
tflog.Debug(ctx, "[create] mak to link", map[string]any{"dependencies": req.Dependencies, "addonIds": dependenciesWithAddonIDs})
for _, dependency := range dependenciesWithAddonIDs {
// TODO: support another apps as dependency

Expand All @@ -114,13 +117,23 @@ func CreateApp(ctx context.Context, req CreateReq) (*CreateRes, diag.Diagnostics
}
}

// Git Deployment
if req.Deployment != nil {
result := gitDeploy(ctx, *req.Deployment, res.Application.DeployURL, &diags)
if diags.HasError() {
return nil, diags
}

tflog.Info(ctx, "### result.EffectivePush: %+v\n", map[string]any{"effectivePush": result.EffectivePush})
tflog.Info(ctx, "### result.DeployedCommit: %+v\n", map[string]any{"deployedCommit": result.ResolvedCommitHash})
res.Commit = result.ResolvedCommitHash
}

return res, diags
}

func UpdateApp(ctx context.Context, req UpdateReq) (*CreateRes, diag.Diagnostics) {
diags := diag.Diagnostics{}

// Application
res := &CreateRes{}

appRes := tmp.UpdateApp(ctx, req.Client, req.Organization, req.ID, req.Application)
Expand Down Expand Up @@ -175,16 +188,17 @@ func UpdateApp(ctx context.Context, req UpdateReq) (*CreateRes, diag.Diagnostics
// TODO: unlink unneeded deps

// Git Deployment (when commit change)
hasBeenPushed := false
if req.Deployment != nil {
diags.Append(gitDeploy(ctx, *req.Deployment, req.Client, res.Application.DeployURL)...)
if diags.HasError() {
return nil, diags
}
result := gitDeploy(ctx, *req.Deployment, res.Application.DeployURL, &diags)
hasBeenPushed = result.EffectivePush
res.Commit = result.ResolvedCommitHash
}

// trigger restart of the app if needed (when env change)
// don't trigger if we just "git push"
// error id 4014 = cannot redeploy an application which has never been deployed yet (did you git push?)
if req.TriggerRestart {
if req.TriggerRestart && !hasBeenPushed {
restartRes := tmp.RestartApp(ctx, req.Client, req.Organization, res.Application.ID)
if restartRes.HasError() && !strings.Contains(restartRes.Error().Error(), "4014") {
diags.AddError("failed to restart app", restartRes.Error().Error())
Expand Down
70 changes: 42 additions & 28 deletions pkg/application/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,47 @@ import (
"github.com/go-git/go-git/v5/storage/memory"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-log/tflog"
"go.clever-cloud.dev/client"
)

func gitDeploy(ctx context.Context, d Deployment, cc *client.Client, cleverRemote string) diag.Diagnostics {
var diags diag.Diagnostics
type GitDeployResult struct {
ResolvedCommitHash string // filled only if no commit is provided to gitDeploy()
EffectivePush bool
}

func gitDeploy(ctx context.Context, d Deployment, cleverRemote string, diags *diag.Diagnostics) GitDeployResult {
var result GitDeployResult

for range 5 {
diags = _gitDeploy(ctx, d, cc, cleverRemote)
result = _gitDeploy(ctx, d, cleverRemote, diags)
if !diags.HasError() {
break
}

time.Sleep(3 * time.Second)
}
return diags
return result
}

func _gitDeploy(ctx context.Context, d Deployment, cc *client.Client, cleverRemote string) diag.Diagnostics {
// Clone, add a remote, checkout and push the code to clever
// EffectivePush is true if there is really something pushed
// ResolvedCommitHash is the commit hash that was pushed if no commit was provided
func _gitDeploy(ctx context.Context, d Deployment, cleverRemote string, diags *diag.Diagnostics) GitDeployResult {
result := GitDeployResult{EffectivePush: false}
cleverRemote = strings.Replace(cleverRemote, "git+ssh", "https", 1) // switch protocol
tflog.Info(ctx, "DEPLOY", map[string]any{
"repository": d.Repository,
"commit": d.GetCommit(),
})

repo, diags := OpenOrClone(ctx, d.Repository, d.Commit)
repo := OpenOrClone(ctx, d.Repository, d.Commit, diags)
if diags.HasError() {
return diags
return result
}

currentRef, err := repo.Head()
if err != nil {
diags.AddError("failed to get current ref", err.Error())
return diags
return result
}

remoteOpts := &config.RemoteConfig{
Expand All @@ -59,7 +71,7 @@ func _gitDeploy(ctx context.Context, d Deployment, cc *client.Client, cleverRemo
remote, err := repo.CreateRemote(remoteOpts)
if err != nil {
diags.AddError("failed to add clever remote", err.Error())
return diags
return result
}

pushOptions := &git.PushOptions{
Expand All @@ -84,11 +96,11 @@ func _gitDeploy(ctx context.Context, d Deployment, cc *client.Client, cleverRemo
commit, err := repo.CommitObject(plumbing.NewHash(refNameOrCommit))
if err == plumbing.ErrObjectNotFound {
diags.AddError("requested commit not found", fmt.Sprintf("no commit '%s'", refNameOrCommit))
return diags
return result
}
if err != nil {
diags.AddError("failed to look for commit", err.Error())
return diags
return result
}

refSpec = config.RefSpec(fmt.Sprintf("%s:%s", commit.Hash.String(), plumbing.Master))
Expand All @@ -101,22 +113,25 @@ func _gitDeploy(ctx context.Context, d Deployment, cc *client.Client, cleverRemo
ref, err := repo.Storer.Reference(plumbing.ReferenceName(refNameOrCommit))
if err == plumbing.ErrReferenceNotFound {
diags.AddError("requested reference not found", fmt.Sprintf("no reference named '%s'", refNameOrCommit))
return diags
return result
}
if err != nil {
diags.AddError("failed to get reference", err.Error())
return diags
return result
}

refSpec = config.RefSpec(fmt.Sprintf("%s:%s", ref.Hash().String(), plumbing.Master))
}

if err := refSpec.Validate(); err != nil {
diags.AddError("failed to build ref spec to push", err.Error())
return diags
return result
}

pushOptions.RefSpecs = []config.RefSpec{refSpec}
} else {
// send current commit
result.ResolvedCommitHash = currentRef.Hash().String()
}

tflog.Debug(ctx, "pushing...", map[string]any{
Expand All @@ -130,38 +145,37 @@ func _gitDeploy(ctx context.Context, d Deployment, cc *client.Client, cleverRemo
} else {
diags.AddError("failed to push to clever remote", err.Error())
}
} else {
result.EffectivePush = true
}

return diags
return result
}

func IsSHA1(s string) bool {
h, err := hex.DecodeString(s)
return err == nil && len(h) == sha1.Size
}

func OpenOrClone(ctx context.Context, repoUrl string, commit *string) (*git.Repository, diag.Diagnostics) {
func OpenOrClone(ctx context.Context, repoUrl string, commit *string, diags *diag.Diagnostics) *git.Repository {
if strings.HasPrefix(repoUrl, "file://") {
return open(repoUrl)
return open(repoUrl, diags)
}

return clone(ctx, repoUrl, commit)
return clone(ctx, repoUrl, commit, diags)
}

func open(repoUrl string) (*git.Repository, diag.Diagnostics) {
diags := diag.Diagnostics{}

func open(repoUrl string, diags *diag.Diagnostics) *git.Repository {
repo, err := git.PlainOpen(strings.TrimPrefix(repoUrl, "file://"))
if err != nil {
diags.AddError("failed to open repository", fmt.Sprintf("cannot open '%s': %s", repoUrl, err.Error()))
return nil, diags
return nil
}

return repo, diags
return repo
}

func clone(ctx context.Context, repoUrl string, commit *string) (*git.Repository, diag.Diagnostics) {
diags := diag.Diagnostics{}
func clone(ctx context.Context, repoUrl string, commit *string, diags *diag.Diagnostics) *git.Repository {
fs := memory.NewStorage()
wt := memfs.New()

Expand All @@ -178,8 +192,8 @@ func clone(ctx context.Context, repoUrl string, commit *string) (*git.Repository
r, err := git.CloneContext(ctx, fs, wt, cloneOpts)
if err != nil {
diags.AddError("failed to clone repository", err.Error())
return nil, diags
return nil
}

return r, diags
return r
}
2 changes: 2 additions & 0 deletions pkg/attributes/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ var blocks = map[string]schema.Block{
},
"commit": schema.StringAttribute{
Optional: true,
Required: false,
Computed: true, // if user provider repo but no commit, we will resolve last one when "git push"
Description: "The git reference you want to deploy",
MarkdownDescription: "Support multiple syntax like `refs/heads/[BRANCH]` or `[COMMIT]`, in most of the case, you can use `refs/heads/master`",
Validators: []validator.String{
Expand Down
12 changes: 12 additions & 0 deletions pkg/attributes/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ func (r Runtime) VHostsAsStrings(ctx context.Context, diags *diag.Diagnostics) [
return vhosts
}

// Set commit in Deployment block if not empty
func (r *Runtime) SetCommit(commit string) {
if commit == "" {
return
}

if r.Deployment == nil {
r.Deployment = &Deployment{}
}
r.Deployment.Commit = pkg.FromStr(commit)
}

// This attributes are used on several runtimes
var runtimeCommon = map[string]schema.Attribute{
// client provided
Expand Down
5 changes: 2 additions & 3 deletions pkg/resources/docker/crud.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,7 @@ func (r *ResourceDocker) Create(ctx context.Context, req resource.CreateRequest,

// Read resource information
func (r *ResourceDocker) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var state Docker

resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
state := helper.StateFrom[Docker](ctx, req.State, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
Expand All @@ -151,6 +149,7 @@ func (r *ResourceDocker) Read(ctx context.Context, req resource.ReadRequest, res
state.Region = pkg.FromStr(app.App.Zone)
state.DeployURL = pkg.FromStr(app.App.DeployURL)
state.BuildFlavor = app.GetBuildFlavor()
state.SetCommit(app.App.CommitID)

vhosts := app.App.Vhosts.AsString()
state.VHosts = pkg.FromSetString(vhosts, &resp.Diagnostics)
Expand Down
1 change: 1 addition & 0 deletions pkg/resources/golang/crud.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ func (r *ResourceGo) Read(ctx context.Context, req resource.ReadRequest, res *re
state.BuildFlavor = appRes.GetBuildFlavor()
state.StickySessions = pkg.FromBool(appRes.App.StickySessions)
state.RedirectHTTPS = pkg.FromBool(application.ToForceHTTPS(appRes.App.ForceHTTPS))
state.SetCommit(appRes.App.CommitID)

vhosts := appRes.App.Vhosts.AsString()
state.VHosts = pkg.FromSetString(vhosts, &res.Diagnostics)
Expand Down
1 change: 1 addition & 0 deletions pkg/resources/java/crud.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ func (r *ResourceJava) Read(ctx context.Context, req resource.ReadRequest, resp
state.Region = pkg.FromStr(readRes.App.Zone)
state.DeployURL = pkg.FromStr(readRes.App.DeployURL)
state.BuildFlavor = readRes.GetBuildFlavor()
state.SetCommit(readRes.App.CommitID)

vhosts := readRes.App.Vhosts.AsString()
state.VHosts = pkg.FromSetString(vhosts, &resp.Diagnostics)
Expand Down
1 change: 1 addition & 0 deletions pkg/resources/nodejs/crud.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ func (r *ResourceNodeJS) Read(ctx context.Context, req resource.ReadRequest, res
state.MaxInstanceCount = basetypes.NewInt64Value(int64(appRes.App.Instance.MaxInstances))
state.SmallestFlavor = pkg.FromStr(appRes.App.Instance.MinFlavor.Name)
state.BiggestFlavor = pkg.FromStr(appRes.App.Instance.MaxFlavor.Name)
state.SetCommit(appRes.App.CommitID)

vhosts := appRes.App.Vhosts.AsString()
state.VHosts = pkg.FromSetString(vhosts, &resp.Diagnostics)
Expand Down
1 change: 1 addition & 0 deletions pkg/resources/php/crud.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ func (r *ResourcePHP) Read(ctx context.Context, req resource.ReadRequest, resp *
state.Region = pkg.FromStr(appPHP.App.Zone)
state.DeployURL = pkg.FromStr(appPHP.App.DeployURL)
state.BuildFlavor = appPHP.GetBuildFlavor()
state.SetCommit(appPHP.App.CommitID)

vhosts := appPHP.App.Vhosts.AsString()
state.VHosts = pkg.FromSetString(vhosts, &resp.Diagnostics)
Expand Down
1 change: 1 addition & 0 deletions pkg/resources/play2/crud.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ func (r *ResourcePlay2) Read(ctx context.Context, req resource.ReadRequest, resp
state.Region = pkg.FromStr(readRes.App.Zone)
state.DeployURL = pkg.FromStr(readRes.App.DeployURL)
state.BuildFlavor = readRes.GetBuildFlavor()
state.SetCommit(readRes.App.CommitID)

vhosts := readRes.App.Vhosts.AsString()
state.VHosts = pkg.FromSetString(vhosts, &resp.Diagnostics)
Expand Down
9 changes: 9 additions & 0 deletions pkg/resources/python/crud.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ func (r *ResourcePython) Create(ctx context.Context, req resource.CreateRequest,
}
}

tflog.Info(ctx, "plan.Deployment: %+v\n", map[string]any{"deployment": plan.Deployment})
//fmt.Printf("plan.Deployment.Commit: %+v\n", plan.Deployment.Commit)
tflog.Info(ctx, "createRes.Commit: %+v\n", map[string]any{"commit": createRes.Commit})
if (plan.Deployment == nil || plan.Deployment.Commit.IsNull()) && createRes.Commit != "" {
tflog.Info(ctx, "############################ Setting commit to", map[string]any{"commit": createRes.Commit})
plan.SetCommit(createRes.Commit)
}

resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
if resp.Diagnostics.HasError() {
return
Expand All @@ -139,6 +147,7 @@ func (r *ResourcePython) Read(ctx context.Context, req resource.ReadRequest, res
}

state.DeployURL = pkg.FromStr(appRes.App.DeployURL)
state.SetCommit(appRes.App.CommitID)

vhosts := appRes.App.Vhosts.AsString()
state.VHosts = pkg.FromSetString(vhosts, &resp.Diagnostics)
Expand Down
Loading
Loading