Skip to content

Commit

Permalink
Implement Cobra CLI tooling, Viper config tooling (#336)
Browse files Browse the repository at this point in the history
* start pulling out + replacing urfave and config

* replace many many instances of config

* move more stuff => viper

* properly remove urfave

* move some flags to root command

* add testrig commands to root

* alias config file keys

* start adding cli parsing tests

* reorder viper init

* remove config path alias

* fmt

* change config file keys to non-nested

* we're more or less in business now

* tidy up the common func

* go fmt

* get tests passing again

* add note about the cliparsing tests

* reorganize

* update docs with changes

* structure cmd dir better

* rename + move some files around

* fix dangling comma
  • Loading branch information
tsmethurst authored Dec 7, 2021
1 parent 182b4ee commit 0884f89
Show file tree
Hide file tree
Showing 487 changed files with 46,722 additions and 8,886 deletions.
3 changes: 2 additions & 1 deletion .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ steps:
path: /go
commands:
- CGO_ENABLED=0 GTS_DB_TYPE="sqlite" GTS_DB_ADDRESS=":memory:" go test ./...
- CGO_ENABLED=0 ./test/cliparsing.sh
when:
event:
include:
Expand Down Expand Up @@ -115,6 +116,6 @@ trigger:

---
kind: signature
hmac: 8a363baa3c7b5e581bd101a7774422042833b7d297faf5d93c9156cf54a31124
hmac: 3c989818a1940fc572110fa35b76b6ea82e9c45a3b1074e3af6328550f12674c

...
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,12 @@ Finally, to run tests against both database types one after the other, use:
./scripts/test.sh
```

### CLI Tests

In [./test/cliparsing.sh](./test/cliparsing.sh) there are a bunch of tests for making sure that CLI flags, config, and environment variables get parsed as expected.

Although these tests *are* part of the CI/CD testing process, you probably won't need to worry too much about running them yourself. That is, unless you're messing about with code inside the `main` package in `cmd/gotosocial`, or inside the `config` package in `internal/config`.

## Project Structure

For project structure, GoToSocial follows a standard and widely-accepted project layout [defined here](https://github.com/golang-standards/project-layout). As the author writes:
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,14 +196,16 @@ The following libraries and frameworks are used by GoToSocial, with gratitude
- [ReneKroon/ttlcache](https://github.com/ReneKroon/ttlcache); in-memory caching. [MIT License](https://spdx.org/licenses/MIT.html).
- [russross/blackfriday](https://github.com/russross/blackfriday); markdown parsing for statuses. [Simplified BSD License](https://spdx.org/licenses/BSD-2-Clause.html).
- [sirupsen/logrus](https://github.com/sirupsen/logrus); logging. [MIT License](https://spdx.org/licenses/MIT.html).
- [spf13/cobra](https://github.com/spf13/cobra); command-line tooling. [Apache-2.0 License](https://spdx.org/licenses/Apache-2.0.html).
- [spf13/pflag](https://github.com/spf13/pflag); command-line flag utilities. [Apache-2.0 License](https://spdx.org/licenses/Apache-2.0.html).
- [spf13/viper](https://github.com/spf13/viper); configuration management. [Apache-2.0 License](https://spdx.org/licenses/Apache-2.0.html).
- [stretchr/testify](https://github.com/stretchr/testify); test framework. [MIT License](https://spdx.org/licenses/MIT.html).
- [superseriousbusiness/exifremove](https://github.com/superseriousbusiness/exifremove) forked from [scottleedavis/go-exif-remove](https://github.com/scottleedavis/go-exif-remove); EXIF data removal. [MIT License](https://spdx.org/licenses/MIT.html).
- [superseriousbusiness/activity](https://github.com/superseriousbusiness/activity) forked from [go-fed/activity](https://github.com/go-fed/activity); Golang ActivityPub/ActivityStreams library. [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html).
- [superseriousbusiness/oauth2](https://github.com/superseriousbusiness/oauth2) forked from [go-oauth2/oauth2](https://github.com/go-oauth2/oauth2); oauth server framework and token handling. [MIT License](https://spdx.org/licenses/MIT.html).
- [go-swagger/go-swagger](https://github.com/go-swagger/go-swagger); Swagger OpenAPI spec generation. [Apache-2.0 License](https://spdx.org/licenses/Apache-2.0.html).
- [tdewolff/minify](https://github.com/tdewolff/minify); HTML minification. [MIT License](https://spdx.org/licenses/MIT.html).
- [uptrace/bun](https://github.com/uptrace/bun); database ORM. [BSD-2-Clause License](https://spdx.org/licenses/BSD-2-Clause.html).
- [urfave/cli](https://github.com/urfave/cli); command-line interface framework. [MIT License](https://spdx.org/licenses/MIT.html).
- [wagslane/go-password-validator](https://github.com/wagslane/go-password-validator); password strength validation. [MIT License](https://spdx.org/licenses/MIT.html).

### Image Attribution
Expand Down
47 changes: 0 additions & 47 deletions cmd/gotosocial/accountsflags.go

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package cliactions
package action

import (
"context"

"github.com/superseriousbusiness/gotosocial/internal/config"
)

// GTSAction defines one *action* that can be taken by the gotosocial cli command.
// This can be either a long-running action (like server start) or something
// shorter like db init or db inspect.
type GTSAction func(context.Context, *config.Config) error
type GTSAction func(context.Context) error
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import (
"fmt"
"time"

"github.com/superseriousbusiness/gotosocial/internal/cliactions"
"github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/bundb"
Expand All @@ -34,30 +35,30 @@ import (
)

// Create creates a new account in the database using the provided flags.
var Create cliactions.GTSAction = func(ctx context.Context, c *config.Config) error {
dbConn, err := bundb.NewBunDBService(ctx, c)
var Create action.GTSAction = func(ctx context.Context) error {
dbConn, err := bundb.NewBunDBService(ctx)
if err != nil {
return fmt.Errorf("error creating dbservice: %s", err)
}

username, ok := c.AccountCLIFlags[config.UsernameFlag]
if !ok {
username := viper.GetString(config.Keys.AdminAccountUsername)
if username == "" {
return errors.New("no username set")
}
if err := validate.Username(username); err != nil {
return err
}

email, ok := c.AccountCLIFlags[config.EmailFlag]
if !ok {
email := viper.GetString(config.Keys.AdminAccountEmail)
if email == "" {
return errors.New("no email set")
}
if err := validate.Email(email); err != nil {
return err
}

password, ok := c.AccountCLIFlags[config.PasswordFlag]
if !ok {
password := viper.GetString(config.Keys.AdminAccountPassword)
if password == "" {
return errors.New("no password set")
}
if err := validate.NewPassword(password); err != nil {
Expand All @@ -73,14 +74,14 @@ var Create cliactions.GTSAction = func(ctx context.Context, c *config.Config) er
}

// Confirm sets a user to Approved, sets Email to the current UnconfirmedEmail value, and sets ConfirmedAt to now.
var Confirm cliactions.GTSAction = func(ctx context.Context, c *config.Config) error {
dbConn, err := bundb.NewBunDBService(ctx, c)
var Confirm action.GTSAction = func(ctx context.Context) error {
dbConn, err := bundb.NewBunDBService(ctx)
if err != nil {
return fmt.Errorf("error creating dbservice: %s", err)
}

username, ok := c.AccountCLIFlags[config.UsernameFlag]
if !ok {
username := viper.GetString(config.Keys.AdminAccountUsername)
if username == "" {
return errors.New("no username set")
}
if err := validate.Username(username); err != nil {
Expand Down Expand Up @@ -108,14 +109,14 @@ var Confirm cliactions.GTSAction = func(ctx context.Context, c *config.Config) e
}

// Promote sets a user to admin.
var Promote cliactions.GTSAction = func(ctx context.Context, c *config.Config) error {
dbConn, err := bundb.NewBunDBService(ctx, c)
var Promote action.GTSAction = func(ctx context.Context) error {
dbConn, err := bundb.NewBunDBService(ctx)
if err != nil {
return fmt.Errorf("error creating dbservice: %s", err)
}

username, ok := c.AccountCLIFlags[config.UsernameFlag]
if !ok {
username := viper.GetString(config.Keys.AdminAccountUsername)
if username == "" {
return errors.New("no username set")
}
if err := validate.Username(username); err != nil {
Expand All @@ -140,14 +141,14 @@ var Promote cliactions.GTSAction = func(ctx context.Context, c *config.Config) e
}

// Demote sets admin on a user to false.
var Demote cliactions.GTSAction = func(ctx context.Context, c *config.Config) error {
dbConn, err := bundb.NewBunDBService(ctx, c)
var Demote action.GTSAction = func(ctx context.Context) error {
dbConn, err := bundb.NewBunDBService(ctx)
if err != nil {
return fmt.Errorf("error creating dbservice: %s", err)
}

username, ok := c.AccountCLIFlags[config.UsernameFlag]
if !ok {
username := viper.GetString(config.Keys.AdminAccountUsername)
if username == "" {
return errors.New("no username set")
}
if err := validate.Username(username); err != nil {
Expand All @@ -172,14 +173,14 @@ var Demote cliactions.GTSAction = func(ctx context.Context, c *config.Config) er
}

// Disable sets Disabled to true on a user.
var Disable cliactions.GTSAction = func(ctx context.Context, c *config.Config) error {
dbConn, err := bundb.NewBunDBService(ctx, c)
var Disable action.GTSAction = func(ctx context.Context) error {
dbConn, err := bundb.NewBunDBService(ctx)
if err != nil {
return fmt.Errorf("error creating dbservice: %s", err)
}

username, ok := c.AccountCLIFlags[config.UsernameFlag]
if !ok {
username := viper.GetString(config.Keys.AdminAccountUsername)
if username == "" {
return errors.New("no username set")
}
if err := validate.Username(username); err != nil {
Expand All @@ -204,28 +205,28 @@ var Disable cliactions.GTSAction = func(ctx context.Context, c *config.Config) e
}

// Suspend suspends the target account, cleanly removing all of its media, followers, following, likes, statuses, etc.
var Suspend cliactions.GTSAction = func(ctx context.Context, c *config.Config) error {
var Suspend action.GTSAction = func(ctx context.Context) error {
// TODO
return nil
}

// Password sets the password of target account.
var Password cliactions.GTSAction = func(ctx context.Context, c *config.Config) error {
dbConn, err := bundb.NewBunDBService(ctx, c)
var Password action.GTSAction = func(ctx context.Context) error {
dbConn, err := bundb.NewBunDBService(ctx)
if err != nil {
return fmt.Errorf("error creating dbservice: %s", err)
}

username, ok := c.AccountCLIFlags[config.UsernameFlag]
if !ok {
username := viper.GetString(config.Keys.AdminAccountUsername)
if username == "" {
return errors.New("no username set")
}
if err := validate.Username(username); err != nil {
return err
}

password, ok := c.AccountCLIFlags[config.PasswordFlag]
if !ok {
password := viper.GetString(config.Keys.AdminAccountPassword)
if password == "" {
return errors.New("no password set")
}
if err := validate.NewPassword(password); err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,24 @@ import (
"errors"
"fmt"

"github.com/superseriousbusiness/gotosocial/internal/cliactions"
"github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db/bundb"
"github.com/superseriousbusiness/gotosocial/internal/trans"
)

// Export exports info from the database into a file
var Export cliactions.GTSAction = func(ctx context.Context, c *config.Config) error {
dbConn, err := bundb.NewBunDBService(ctx, c)
var Export action.GTSAction = func(ctx context.Context) error {
dbConn, err := bundb.NewBunDBService(ctx)
if err != nil {
return fmt.Errorf("error creating dbservice: %s", err)
}

exporter := trans.NewExporter(dbConn)

path, ok := c.ExportCLIFlags[config.TransPathFlag]
if !ok {
path := viper.GetString(config.Keys.AdminTransPath)
if path == "" {
return errors.New("no path set")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,24 @@ import (
"errors"
"fmt"

"github.com/superseriousbusiness/gotosocial/internal/cliactions"
"github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db/bundb"
"github.com/superseriousbusiness/gotosocial/internal/trans"
)

// Import imports info from a file into the database
var Import cliactions.GTSAction = func(ctx context.Context, c *config.Config) error {
dbConn, err := bundb.NewBunDBService(ctx, c)
var Import action.GTSAction = func(ctx context.Context) error {
dbConn, err := bundb.NewBunDBService(ctx)
if err != nil {
return fmt.Errorf("error creating dbservice: %s", err)
}

importer := trans.NewImporter(dbConn)

path, ok := c.ExportCLIFlags[config.TransPathFlag]
if !ok {
path := viper.GetString(config.Keys.AdminTransPath)
if path == "" {
return errors.New("no path set")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,24 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package main
package config

import (
"github.com/urfave/cli/v2"
"context"
"encoding/json"
"fmt"

"github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action"
)

func getCommands(allFlags []cli.Flag) []*cli.Command {
commands := []*cli.Command{}
commandSets := [][]*cli.Command{
serverCommands(allFlags),
adminCommands(allFlags),
testrigCommands(allFlags),
}
for _, cs := range commandSets {
commands = append(commands, cs...)
// Config just prints the collated config out to stdout as json.
var Config action.GTSAction = func(ctx context.Context) error {
allSettings := viper.AllSettings()
b, err := json.Marshal(&allSettings)
if err != nil {
return err
}

return commands
fmt.Println(string(b))
return nil
}
Loading

0 comments on commit 0884f89

Please sign in to comment.