Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
- name: install dokku acl plugin
run: sudo dokku plugin:install https://github.com/dokku-community/dokku-acl.git acl
- name: run integration tests
run: sudo go test -v -count=1 -run TestIntegration ./tasks/
run: sudo go test -v -count=1 -timeout 20m -run TestIntegration ./tasks/

bats-test:
name: bats-test
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,4 @@ test:

.PHONY: test-integration
test-integration:
go test -v -count=1 -run TestIntegration ./tasks/
go test -v -count=1 -timeout 20m -run TestIntegration ./tasks/
39 changes: 39 additions & 0 deletions docs/dokku_proxy_property.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# dokku_proxy_property

Manages the proxy configuration for a given dokku application

## Setting the proxy type for an app

```yaml
dokku_proxy_property:
app: node-js-app
property: type
value: nginx
```

## Setting the proxy type globally

```yaml
dokku_proxy_property:
app: ""
global: true
property: type
value: haproxy
```

## Setting the proxy port for an app

```yaml
dokku_proxy_property:
app: node-js-app
property: proxy-port
value: "8080"
```

## Clearing the proxy type for an app

```yaml
dokku_proxy_property:
app: node-js-app
property: type
```
2 changes: 1 addition & 1 deletion tasks/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ func TestAllTasksExamplesReturnNoError(t *testing.T) {
}

func TestRegisteredTaskCount(t *testing.T) {
expected := 54
expected := 55
if got := len(RegisteredTasks); got != expected {
t.Errorf("expected %d registered tasks, got %d", expected, got)
}
Expand Down
90 changes: 90 additions & 0 deletions tasks/proxy_property_task.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package tasks

// ProxyPropertyTask manages the proxy configuration for a given dokku application
type ProxyPropertyTask struct {
// App is the name of the app. Required if Global is false.
App string `required:"false" yaml:"app"`

// Global is a flag indicating if the proxy configuration should be applied globally
Global bool `required:"false" yaml:"global,omitempty"`

// Property is the name of the proxy property to set
Property string `required:"true" yaml:"property"`

// Value is the value to set for the proxy property
Value string `required:"false" yaml:"value,omitempty"`

// State is the desired state of the proxy configuration
State State `required:"true" yaml:"state,omitempty" default:"present" options:"present,absent"`
}

// ProxyPropertyTaskExample contains an example of a ProxyPropertyTask
type ProxyPropertyTaskExample struct {
// Name is the task name holding the ProxyPropertyTask description
Name string `yaml:"-"`

// ProxyPropertyTask is the ProxyPropertyTask configuration
ProxyPropertyTask ProxyPropertyTask `yaml:"dokku_proxy_property"`
}

// GetName returns the name of the example
func (e ProxyPropertyTaskExample) GetName() string {
return e.Name
}

// Doc returns the docblock for the proxy property task
func (t ProxyPropertyTask) Doc() string {
return "Manages the proxy configuration for a given dokku application"
}

// Examples returns the examples for the proxy property task
func (t ProxyPropertyTask) Examples() ([]Doc, error) {
return MarshalExamples([]ProxyPropertyTaskExample{
{
Name: "Setting the proxy type for an app",
ProxyPropertyTask: ProxyPropertyTask{
App: "node-js-app",
Property: "type",
Value: "nginx",
},
},
{
Name: "Setting the proxy type globally",
ProxyPropertyTask: ProxyPropertyTask{
Global: true,
Property: "type",
Value: "haproxy",
},
},
{
Name: "Setting the proxy port for an app",
ProxyPropertyTask: ProxyPropertyTask{
App: "node-js-app",
Property: "proxy-port",
Value: "8080",
},
},
{
Name: "Clearing the proxy type for an app",
ProxyPropertyTask: ProxyPropertyTask{
App: "node-js-app",
Property: "type",
},
},
})
}

// Execute sets or unsets the proxy property
func (t ProxyPropertyTask) Execute() TaskOutputState {
return ExecutePlan(t.Plan())
}

// Plan reports the drift the ProxyPropertyTask would produce.
func (t ProxyPropertyTask) Plan() PlanResult {
return planProperty(t.State, t.App, t.Global, t.Property, t.Value, "proxy:set")
}

// init registers the ProxyPropertyTask with the task registry
func init() {
RegisterTask(&ProxyPropertyTask{})
}
62 changes: 62 additions & 0 deletions tasks/proxy_property_task_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package tasks

import (
"testing"
)

func TestIntegrationProxyProperty(t *testing.T) {
skipIfNoDokkuT(t)

appName := "docket-test-proxy-prop"

destroyApp(appName)
createApp(appName)
defer destroyApp(appName)

// set proxy type
setTask := ProxyPropertyTask{
App: appName,
Property: "type",
Value: "nginx",
State: StatePresent,
}
result := setTask.Execute()
if result.Error != nil {
t.Fatalf("failed to set proxy property: %v", result.Error)
}
if result.State != StatePresent {
t.Errorf("expected state 'present', got '%s'", result.State)
}

// re-applying the same value should be a no-op
result = setTask.Execute()
if result.Error != nil {
t.Fatalf("failed to re-apply proxy property: %v", result.Error)
}
if result.Changed {
t.Errorf("expected re-apply to report Changed=false")
}

// unset proxy type
unsetTask := ProxyPropertyTask{
App: appName,
Property: "type",
State: StateAbsent,
}
result = unsetTask.Execute()
if result.Error != nil {
t.Fatalf("failed to unset proxy property: %v", result.Error)
}
if result.State != StateAbsent {
t.Errorf("expected state 'absent', got '%s'", result.State)
}

// re-applying the absent state should be a no-op
result = unsetTask.Execute()
if result.Error != nil {
t.Fatalf("failed to re-apply absent proxy property: %v", result.Error)
}
if result.Changed {
t.Errorf("expected re-apply absent to report Changed=false")
}
}
71 changes: 71 additions & 0 deletions tasks/proxy_property_task_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package tasks

import (
"strings"
"testing"
)

func TestProxyPropertyTaskInvalidState(t *testing.T) {
task := ProxyPropertyTask{App: "test-app", Property: "type", State: "invalid"}
result := task.Execute()
if result.Error == nil {
t.Fatal("Execute with invalid state should return an error")
}
}

func TestProxyPropertyTaskMissingApp(t *testing.T) {
task := ProxyPropertyTask{Property: "type", Value: "nginx", State: StatePresent}
result := task.Execute()
if result.Error == nil {
t.Fatal("Execute without app and global=false should return an error")
}
}

func TestProxyPropertyTaskGlobalWithAppSet(t *testing.T) {
task := ProxyPropertyTask{
App: "test-app",
Global: true,
Property: "type",
Value: "nginx",
State: StatePresent,
}
result := task.Execute()
if result.Error == nil {
t.Fatal("expected error when both global and app are set")
}
if !strings.Contains(result.Error.Error(), "must not be set when 'global' is set to true") {
t.Errorf("unexpected error: %v", result.Error)
}
}

func TestProxyPropertyTaskPresentWithoutValue(t *testing.T) {
task := ProxyPropertyTask{
App: "test-app",
Property: "type",
Value: "",
State: StatePresent,
}
result := task.Execute()
if result.Error == nil {
t.Fatal("expected error when present state has no value")
}
if !strings.Contains(result.Error.Error(), "invalid without a value") {
t.Errorf("unexpected error: %v", result.Error)
}
}

func TestProxyPropertyTaskAbsentWithValue(t *testing.T) {
task := ProxyPropertyTask{
App: "test-app",
Property: "type",
Value: "nginx",
State: StateAbsent,
}
result := task.Execute()
if result.Error == nil {
t.Fatal("expected error when absent state has a value")
}
if !strings.Contains(result.Error.Error(), "invalid with a value") {
t.Errorf("unexpected error: %v", result.Error)
}
}