Skip to content

Commit

Permalink
chore: closes #38
Browse files Browse the repository at this point in the history
  • Loading branch information
YuukanOO committed Nov 27, 2023
1 parent 825cd84 commit 023e4eb
Show file tree
Hide file tree
Showing 17 changed files with 114 additions and 58 deletions.
6 changes: 3 additions & 3 deletions cmd/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ func (c configuration) RunnersPollInterval() time.Duration { return c.pol
func (c configuration) RunnersDeploymentCount() int { return c.Runners.Deployment }

func (c configuration) IsSecure() bool {
// If secure has been explicitly set, returns it
if c.Http.Secure.HasValue() {
return c.Http.Secure.MustGet()
// If secure has been explicitly isSet, returns it
if secure, isSet := c.Http.Secure.TryGet(); isSet {
return secure
}

// Else, fallback to the domain SSL value
Expand Down
8 changes: 4 additions & 4 deletions cmd/serve/deployments.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ func (s *server) queueDeploymentHandler() gin.HandlerFunc {
)

// Resolve the payload data.
if body.Git.HasValue() {
payload = body.Git.MustGet()
} else if body.Raw.HasValue() {
payload = body.Raw.MustGet()
if gitBody, isSet := body.Git.TryGet(); isSet {
payload = gitBody
} else if rawBody, isSet := body.Raw.TryGet(); isSet {
payload = rawBody
} else if body.Archive != nil {
payload = body.Archive
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/serve/front/src/lib/localization/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Cette action est IRRÉVERSIBLE et supprimera TOUTES LES DONNÉES associées : co
`Aucune variable pour l'environnement <strong>${name}</strong>.`,
'app.cleanup_requested': 'Suppression demandée',
'app.cleanup_requested.description': function (date: DateValue) {
return `La suppression de l'application a été demandé le ${this.date(
return `La suppression de l'application a été demandée le ${this.date(
date
)} et sera traitée sous peu.`;
},
Expand Down
4 changes: 2 additions & 2 deletions internal/auth/app/command/update_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ func UpdateUser(
user.HasEmail(uniqueEmail)
}

if cmd.Password.HasValue() {
hash, err := hasher.Hash(cmd.Password.MustGet())
if newPassword, isSet := cmd.Password.TryGet(); isSet {
hash, err := hasher.Hash(newPassword)

if err != nil {
return err
Expand Down
7 changes: 3 additions & 4 deletions internal/deployment/app/command/create_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,11 @@ func CreateApp(

app := domain.NewApp(uniqueName, auth.CurrentUser(ctx).MustGet())

if cmd.VCS.HasValue() {
if cmdVCS, isSet := cmd.VCS.TryGet(); isSet {
vcs := domain.NewVCSConfig(url)
cmdVCS := cmd.VCS.MustGet()

if cmdVCS.Token.HasValue() {
vcs = vcs.Authenticated(cmdVCS.Token.MustGet())
if token, isSet := cmdVCS.Token.TryGet(); isSet {
vcs = vcs.Authenticated(token)
}

app.UseVersionControl(vcs)
Expand Down
23 changes: 11 additions & 12 deletions internal/deployment/app/command/update_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,31 +54,30 @@ func UpdateApp(
return err
}

if cmd.VCS.IsSet() {
if cmd.VCS.IsNil() {
app.RemoveVersionControl()
} else {
vcsPatch := cmd.VCS.MustGet()

if !app.VCS().HasValue() && !vcsPatch.Url.HasValue() {
if vcsPatch, isSet := cmd.VCS.TryGet(); isSet {
if vcsUpdate, hasValue := vcsPatch.TryGet(); hasValue {
// No VCS configured on the app and no url given
if !app.VCS().HasValue() && !vcsUpdate.Url.HasValue() {
return domain.ErrVCSNotConfigured
}

vcs := app.VCS().Get(domain.NewVCSConfig(url))

if vcsPatch.Url.HasValue() {
if vcsUpdate.Url.HasValue() {
vcs = vcs.WithUrl(url)
}

if vcsPatch.Token.IsSet() {
if vcsPatch.Token.IsNil() {
vcs = vcs.Public()
if tokenPatch, isSet := vcsUpdate.Token.TryGet(); isSet {
if token, hasValue := tokenPatch.TryGet(); hasValue {
vcs = vcs.Authenticated(token)
} else {
vcs = vcs.Authenticated(vcsPatch.Token.MustGet())
vcs = vcs.Public()
}
}

app.UseVersionControl(vcs)
} else {
app.RemoveVersionControl()
}
}

Expand Down
22 changes: 12 additions & 10 deletions internal/deployment/domain/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,18 +122,18 @@ func AppFrom(scanner storage.Scanner) (a App, err error) {

a.created = shared.ActionFrom(createdBy, createdAt)

if cleanupRequestedAt.HasValue() {
if requestedAt, isSet := cleanupRequestedAt.TryGet(); isSet {
a.cleanupRequested = a.cleanupRequested.WithValue(
shared.ActionFrom(domain.UserID(cleanupRequestedBy.MustGet()), cleanupRequestedAt.MustGet()),
shared.ActionFrom(domain.UserID(cleanupRequestedBy.MustGet()), requestedAt),
)
}

// vcs url has been set, reconstitute the vcs config
if url.HasValue() {
vcs := NewVCSConfig(url.MustGet())
if u, isSet := url.TryGet(); isSet {
vcs := NewVCSConfig(u)

if token.HasValue() {
vcs = vcs.Authenticated(token.MustGet())
if tok, isSet := token.TryGet(); isSet {
vcs = vcs.Authenticated(tok)
}

a.vcs = a.vcs.WithValue(vcs)
Expand All @@ -144,7 +144,7 @@ func AppFrom(scanner storage.Scanner) (a App, err error) {

// Sets an app version control configuration.
func (a *App) UseVersionControl(config VCSConfig) {
if a.vcs.HasValue() && config.Equals(a.vcs.MustGet()) {
if existing, isSet := a.vcs.TryGet(); isSet && config.Equals(existing) {
return
}

Expand All @@ -167,7 +167,7 @@ func (a *App) RemoveVersionControl() {

// Store environement variables per env and per services for this application.
func (a *App) HasEnvironmentVariables(vars EnvironmentsEnv) {
if a.env.HasValue() && vars.Equals(a.env.MustGet()) {
if existing, isSet := a.env.TryGet(); isSet && vars.Equals(existing) {
return
}

Expand Down Expand Up @@ -223,11 +223,13 @@ func (a App) VCS() monad.Maybe[VCSConfig] { return a.vcs }

// Retrieve environments variables per service for the given deployment environment
func (a App) envFor(e Environment) (m monad.Maybe[ServicesEnv]) {
if !a.env.HasValue() {
env, isSet := a.env.TryGet()

if !isSet {
return m
}

vars, exists := a.env.MustGet()[e]
vars, exists := env[e]

if !exists {
return m
Expand Down
6 changes: 4 additions & 2 deletions internal/deployment/domain/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ func (c Config) Env() monad.Maybe[ServicesEnv] { return c.env } // FIXME: If I w
// Retrieve environment variables associated with the given service name.
// FIXME: If I want to follow my mantra, it should returns a readonly map
func (c Config) EnvironmentVariablesFor(service string) (m monad.Maybe[EnvVars]) {
if !c.env.HasValue() {
env, isSet := c.env.TryGet()

if !isSet {
return m
}

vars, exists := c.env.MustGet()[service]
vars, exists := env[service]

if !exists {
return m
Expand Down
3 changes: 1 addition & 2 deletions internal/deployment/infra/backend/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,8 +436,7 @@ func (d *docker) generateProject(depl domain.Deployment, dir string, logger doma
// Attach environment variables if any
servicesEnv := config.EnvironmentVariablesFor(deployedService.Name())

if servicesEnv.HasValue() {
vars := servicesEnv.MustGet()
if vars, hasVars := servicesEnv.TryGet(); hasVars {
envNames := make([]string, 0, len(vars))

for name, value := range vars {
Expand Down
22 changes: 12 additions & 10 deletions internal/deployment/infra/source/git/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,14 @@ func (s *service) Prepare(app domain.App, payload any) (domain.SourceData, error
return nil, err
}

if !app.VCS().HasValue() {
vcs, hasVCS := app.VCS().TryGet()

if !hasVCS {
return nil, domain.ErrVCSNotConfigured
}

// Retrieve the latest commit to make sure the branch exists
latestCommit, err := getLatestBranchCommit(app.VCS().MustGet(), req.Branch)
latestCommit, err := getLatestBranchCommit(vcs, req.Branch)

if err != nil {
return nil, validation.WrapIfAppErr(err, "branch")
Expand All @@ -89,26 +91,26 @@ func (s *service) Fetch(ctx context.Context, dir string, logger domain.Deploymen
return ErrAppRetrievedFailed
}

vcs, hasVCS := app.VCS().TryGet()

// Could happen if the app vcs config has been removed since the deployment has been queued
if !app.VCS().HasValue() {
if !hasVCS {
return domain.ErrVCSNotConfigured
}

config := app.VCS().MustGet()

data, ok := depl.Source().(Data)

if !ok {
return domain.ErrInvalidSourcePayload
}

logger.Stepf("cloning branch %s at %s from %s using token: %t", data.Branch, data.Hash, config.Url(), config.Token().HasValue())
logger.Stepf("cloning branch %s at %s from %s using token: %t", data.Branch, data.Hash, vcs.Url(), vcs.Token().HasValue())

r, err := git.PlainCloneContext(ctx, dir, false, &git.CloneOptions{
Auth: getAuthMethod(config),
Auth: getAuthMethod(vcs),
SingleBranch: true,
ReferenceName: plumbing.NewBranchReferenceName(data.Branch),
URL: config.Url().String(),
URL: vcs.Url().String(),
Progress: logger,
})

Expand Down Expand Up @@ -143,10 +145,10 @@ func (s *service) Fetch(ctx context.Context, dir string, logger domain.Deploymen
}

func getAuthMethod(vcs domain.VCSConfig) transport.AuthMethod {
if vcs.Token().HasValue() {
if token, isSet := vcs.Token().TryGet(); isSet {
return &http.BasicAuth{
Username: basicAuthUser,
Password: vcs.Token().MustGet(),
Password: token,
}
}

Expand Down
4 changes: 2 additions & 2 deletions internal/deployment/infra/sqlite/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,9 @@ func appDetailDataMapper(s storage.Scanner) (a query.AppDetail, err error) {

a.Environments = make(map[string]query.Deployment)

if url.HasValue() {
if u, isSet := url.TryGet(); isSet {
a.VCS = a.VCS.WithValue(query.VCSConfig{
Url: url.MustGet(),
Url: u,
Token: token,
})
}
Expand Down
5 changes: 5 additions & 0 deletions pkg/monad/maybe.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ func (m Maybe[T]) MustGet() T {
return m.value
}

// Get the inner value and a boolean indicating if it has been set.
func (m Maybe[T]) TryGet() (T, bool) {
return m.value, m.hasValue
}

// Retrieve the inner value or the fallback if it doesn't have one.
func (m Maybe[T]) Get(fallback T) T {
if !m.hasValue {
Expand Down
16 changes: 16 additions & 0 deletions pkg/monad/maybe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ func Test_Maybe(t *testing.T) {
testutil.IsTrue(t, m.HasValue())
})

t.Run("could returns its internal value and a boolean indicating if it has been set", func(t *testing.T) {
var m monad.Maybe[string]

value, hasValue := m.TryGet()

testutil.IsFalse(t, hasValue)
testutil.Equals(t, "", value)

m = m.WithValue("ok")

value, hasValue = m.TryGet()

testutil.IsTrue(t, hasValue)
testutil.Equals(t, "ok", value)
})

t.Run("could be assigned a value", func(t *testing.T) {
var (
m monad.Maybe[time.Time]
Expand Down
6 changes: 6 additions & 0 deletions pkg/monad/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ func Nil[T any]() (p Patch[T]) {
func (p Patch[T]) IsSet() bool { return p.isSet }
func (p Patch[T]) IsNil() bool { return p.isSet && !p.hasValue }

// Try to get the inner optional value for this Patch structure. The boolean returns
// if the patch has been set so the returned value may represent a nil value.
func (p Patch[T]) TryGet() (Maybe[T], bool) {
return p.Maybe, p.isSet
}

// Implements the UnmarshalJSON interface.
func (p *Patch[T]) UnmarshalJSON(data []byte) error {
// If we're here, it means the value has been set
Expand Down
22 changes: 22 additions & 0 deletions pkg/monad/patch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,28 @@ func Test_Patch(t *testing.T) {
testutil.IsFalse(t, p.HasValue())
})

t.Run("should return the inner monad and a boolean indicating if it has been set", func(t *testing.T) {
tests := []struct {
name string
value monad.Patch[int]
isSet bool
hasValue bool
}{
{"empty patch", monad.Patch[int]{}, false, false},
{"nil patch", monad.Nil[int](), true, false},
{"patch with a value", monad.PatchValue(42), true, true},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
m, isSet := test.value.TryGet()

testutil.Equals(t, test.isSet, isSet)
testutil.Equals(t, test.hasValue, m.HasValue())
})
}
})

t.Run("should correctly handle a JSON when unmarshalling", func(t *testing.T) {
tests := []struct {
json string
Expand Down
6 changes: 4 additions & 2 deletions pkg/storage/sqlite/builder/statements.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ import (
// if the monad value is set. This is useful for optional fields in a query.
func Maybe[T any](value monad.Maybe[T], fn func(T) (string, []any)) Statement {
return func(builder sqlBuilder) {
if !value.HasValue() {
v, hasValue := value.TryGet()

if !hasValue {
return
}

sql, args := fn(value.MustGet())
sql, args := fn(v)

builder.apply(sql, args...)
}
Expand Down
10 changes: 6 additions & 4 deletions pkg/validation/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ func If(expr bool, fn func() error) error {

// Same as If but executes the fn if the monad has a value.
func Maybe[T any](m monad.Maybe[T], fn func(T) error) error {
if m.HasValue() {
return fn(m.MustGet())
if value, isSet := m.TryGet(); isSet {
return fn(value)
}

return nil
Expand All @@ -119,8 +119,10 @@ func Maybe[T any](m monad.Maybe[T], fn func(T) error) error {
// specific case.
// FIXME: When go can infer correctly from an interface [T], merge Maybe and Patch.
func Patch[T any](p monad.Patch[T], fn func(T) error) error {
if p.HasValue() {
return fn(p.MustGet())
if maybeValue, isSet := p.TryGet(); isSet {
if value, hasValue := maybeValue.TryGet(); hasValue {
return fn(value)
}
}

return nil
Expand Down

0 comments on commit 023e4eb

Please sign in to comment.