Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6189117
Add up and down command
praem90 Jul 3, 2025
0322b70
Use file helper to create files and add unit tests
praem90 Jul 3, 2025
1bba742
Fix the foundation.App dependency
praem90 Sep 14, 2025
6b4b5f3
Use support/path instead of foundation.App
praem90 Sep 14, 2025
ca71389
Add unit test case
praem90 Sep 14, 2025
7a4b575
Add some missing checks
praem90 Sep 14, 2025
1be06c2
Add more missing checks
praem90 Sep 14, 2025
04040a9
One more
praem90 Sep 14, 2025
b1c522b
Fix tmpfile path
praem90 Sep 14, 2025
b9af633
Use T.TempDir instead of os.TempDir in tests
praem90 Sep 15, 2025
8f3cb8a
Add reason to the down command
praem90 Sep 15, 2025
4e49d50
Add option to the tests
praem90 Sep 15, 2025
f9002ab
Change the maintenance file name
praem90 Sep 15, 2025
e3ff849
close created file handles
praem90 Sep 15, 2025
e6ef8f2
Defer abort
praem90 Sep 15, 2025
ad5dd35
Fix the linter issue
praem90 Sep 15, 2025
83df880
Add more options to the down command
praem90 Sep 18, 2025
091eaaa
Use options
praem90 Jan 4, 2026
d16a3f0
Check for maintenance mode respond
praem90 Jan 4, 2026
aab13eb
Fix down_command_test
praem90 Jan 5, 2026
7d5341b
Add more unit test cases
praem90 Jan 5, 2026
ab91f52
Fix more lint issues
praem90 Jan 10, 2026
a6295e1
Fix lint issue
praem90 Jan 10, 2026
c650511
fix tests
hwbrzzl Jan 11, 2026
63f223a
fix tests
hwbrzzl Jan 11, 2026
4af9c68
fix tests
hwbrzzl Jan 11, 2026
65fd56a
fix tests
hwbrzzl Jan 11, 2026
c9ed779
Merge branch 'goravel:master' into feat-546-artisan-command-up-and-down
praem90 Jan 26, 2026
08a8e6a
Address PR comments
praem90 Jan 26, 2026
f79be00
Fix check_for_maintenance_test
praem90 Jan 26, 2026
6917e6a
Check Aborts in check_for_maintenance
praem90 Jan 26, 2026
8438cfd
Rename check_for_maintenance_mode
praem90 Jan 26, 2026
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: 2 additions & 0 deletions errors/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,6 @@ var (
ValidationEmptyRules = New("rules can't be empty")
ValidationFilterRegisterFailed = New("filter register failed: %v")
ValidationRuleRegisterFailed = New("rule register failed: %v")

ViewTemplateNotExist = New("view template %s does not exist")
)
2 changes: 2 additions & 0 deletions foundation/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ func (r *Application) BootServiceProviders() {
console.NewPackageInstallCommand(binding.Bindings, r.GetJson()),
console.NewPackageUninstallCommand(binding.Bindings, r.GetJson()),
console.NewVendorPublishCommand(r.publishes, r.publishGroups),
console.NewUpCommand(r),
console.NewDownCommand(r),
})
r.bootArtisan()
}
Expand Down
142 changes: 142 additions & 0 deletions foundation/console/down_command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package console

import (
"encoding/json"
"fmt"
"net/http"

"github.com/goravel/framework/contracts/console"
"github.com/goravel/framework/contracts/console/command"
"github.com/goravel/framework/contracts/foundation"
"github.com/goravel/framework/contracts/hash"
"github.com/goravel/framework/contracts/view"
"github.com/goravel/framework/errors"
"github.com/goravel/framework/support/file"
"github.com/goravel/framework/support/path"
"github.com/goravel/framework/support/str"
)

type DownCommand struct {
app foundation.Application
view view.View
hash hash.Hash
}

type MaintenanceOptions struct {
Reason string `json:"reason,omitempty"`
Redirect string `json:"redirect,omitempty"`
Render string `json:"render,omitempty"`
Secret string `json:"secret,omitempty"`
Status int `json:"status"`
}

func NewDownCommand(app foundation.Application) *DownCommand {
return &DownCommand{app, app.MakeView(), app.MakeHash()}
}

// Signature The name and signature of the console command.
func (r *DownCommand) Signature() string {
return "down"
}

// Description The console command description.
func (r *DownCommand) Description() string {
return "Put the application into maintenance mode"
}

// Extend The console command extend.
func (r *DownCommand) Extend() command.Extend {
return command.Extend{
Flags: []command.Flag{
&command.StringFlag{
Name: "reason",
Usage: "The reason for maintenance to show in the response",
Value: "The application is under maintenance",
},
&command.StringFlag{
Name: "redirect",
Usage: "The path that the user should be redirected to",
},
&command.StringFlag{
Name: "render",
Usage: "The view should be prerendered for display during maintenance mode",
},
&command.StringFlag{
Name: "secret",
Usage: "The secret phrase that may be used to bypass the maintenance mode",
},
&command.BoolFlag{
Name: "with-secret",
Usage: "Generate a random secret phrase that may be used to bypass the maintenance mode",
},
&command.IntFlag{
Name: "status",
Usage: "The status code that should be used when returning the maintenance mode response",
Value: http.StatusServiceUnavailable,
},
},
}
}

// Handle Execute the console command.
func (r *DownCommand) Handle(ctx console.Context) error {
path := path.Storage("framework/maintenance")

options := MaintenanceOptions{}

options.Status = ctx.OptionInt("status")

options.Redirect = ctx.Option("redirect")

if render := ctx.Option("render"); render != "" {
if r.view.Exists(render) {
options.Render = render
} else {
ctx.Error(errors.ViewTemplateNotExist.Args(render).Error())
return nil
}
}

if options.Redirect == "" && options.Render == "" {
options.Reason = ctx.Option("reason")
}

if secret := ctx.Option("secret"); secret != "" {
hash, err := r.hash.Make(secret)
if err != nil {
ctx.Error(err.Error())
return nil
} else {
options.Secret = hash
}
}

if withSecret := ctx.OptionBool("with-secret"); withSecret {
secret := str.Random(40)
hash, err := r.app.MakeHash().Make(secret)

if err != nil {
ctx.Error(err.Error())
return nil
} else {
options.Secret = hash
ctx.Info(fmt.Sprintf("Using secret: %s", secret))
}
}

jsonBytes, err := json.Marshal(options)

if err != nil {
ctx.Error(err.Error())
return nil
}

if err := file.PutContent(path, string(jsonBytes)); err != nil {
ctx.Error(err.Error())
return nil
}

ctx.Success("The application is in maintenance mode now")

return nil
}
Loading
Loading