mirror of
https://github.com/dokku/dokku.git
synced 2026-07-10 12:36:13 +02:00
feat: add --format json support to plugin:list
Adds a `--format json` flag to `plugin:list` whose output includes each plugin's install source - for git-based third-party plugins, the git remote URL, the checked-out commit, and the followed branch - so the set of installed plugins can be reconstructed elsewhere. Closes #8798.
This commit is contained in:
@@ -9,7 +9,7 @@ plugin:enable <name> # Enable a previously disabled plugin
|
||||
plugin:install [--core|git-url] [--committish branch|commit|tag] [--name custom-plugin-name] [--skip-install-trigger] # Optionally download git-url (and pin to the specified branch/commit/tag) & run install trigger for active plugins (or only core ones)
|
||||
plugin:installed <name> # Checks if a plugin is installed
|
||||
plugin:install-dependencies [--core] # Run install-dependencies trigger for active plugins (or only core ones)
|
||||
plugin:list # Print active plugins
|
||||
plugin:list [--format stdout|json] # Print active plugins
|
||||
plugin:trigger <args...>. # Trigger an arbitrary plugin hook
|
||||
plugin:uninstall <name> # Uninstall a plugin (third-party only)
|
||||
plugin:update [name [branch|commit|tag]] # Optionally update named plugin from git (and pin to the specified branch/commit/tag) & run update trigger for active plugins
|
||||
@@ -67,6 +67,39 @@ plugn: dev
|
||||
trace 0.38.21 enabled dokku core trace plugin
|
||||
```
|
||||
|
||||
The list can also be emitted as JSON via the `--format json` flag. In addition to the name, version, enabled state, and description shown in the default output, the JSON output includes whether a plugin is a core plugin and - for git-based third-party plugins - the install source (the git remote URL, the currently checked-out commit, and the followed branch). This is useful for tooling that reconstructs a server's set of installed plugins:
|
||||
|
||||
```shell
|
||||
dokku plugin:list --format json
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "apps",
|
||||
"version": "0.38.21",
|
||||
"enabled": true,
|
||||
"core": true,
|
||||
"description": "dokku core apps plugin",
|
||||
"source_url": "",
|
||||
"committish": "",
|
||||
"branch": ""
|
||||
},
|
||||
{
|
||||
"name": "postgres",
|
||||
"version": "1.42.0",
|
||||
"enabled": true,
|
||||
"core": false,
|
||||
"description": "dokku postgres service plugin",
|
||||
"source_url": "https://github.com/dokku/dokku-postgres.git",
|
||||
"committish": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0",
|
||||
"branch": "master"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
The `source_url`, `committish`, and `branch` fields are only populated for plugins installed from a git repository. They are empty for core plugins as well as for plugins installed from a tarball or a local `file://` path. When a plugin is pinned to a specific commit or tag (a detached checkout), the `branch` field is empty while `committish` still reports the exact commit.
|
||||
|
||||
> [!WARNING]
|
||||
> All plugin commands other than `plugin:list` and `plugin:help` require sudo access and must be run directly from the Dokku server.
|
||||
|
||||
|
||||
1
go.work
1
go.work
@@ -12,6 +12,7 @@ use (
|
||||
./plugins/logs
|
||||
./plugins/network
|
||||
./plugins/nginx-vhosts
|
||||
./plugins/plugin
|
||||
./plugins/ports
|
||||
./plugins/proxy
|
||||
./plugins/ps
|
||||
|
||||
1
plugins/plugin/.gitignore
vendored
Normal file
1
plugins/plugin/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/plugin-list
|
||||
11
plugins/plugin/Makefile
Normal file
11
plugins/plugin/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
GOARCH ?= amd64
|
||||
BUILD = plugin-list
|
||||
PLUGIN_NAME = plugin
|
||||
|
||||
clean-plugin-list:
|
||||
rm -rf plugin-list
|
||||
|
||||
plugin-list: clean-plugin-list **/**/plugin-list.go
|
||||
GOARCH=$(GOARCH) go build -ldflags="-s -w" $(GO_ARGS) -o plugin-list src/plugin-list/plugin-list.go
|
||||
|
||||
include ../../common.mk
|
||||
29
plugins/plugin/go.mod
Normal file
29
plugins/plugin/go.mod
Normal file
@@ -0,0 +1,29 @@
|
||||
module github.com/dokku/dokku/plugins/plugin
|
||||
|
||||
go 1.26.2
|
||||
|
||||
require (
|
||||
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
|
||||
github.com/spf13/pflag v1.0.10
|
||||
golang.org/x/sync v0.21.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/alexellis/go-execute/v2 v2.2.1 // indirect
|
||||
github.com/fatih/color v1.19.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/melbahja/goph v1.5.1 // indirect
|
||||
github.com/otiai10/copy v1.14.1 // indirect
|
||||
github.com/otiai10/mint v1.6.3 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/sftp v1.13.10 // indirect
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible // indirect
|
||||
golang.org/x/crypto v0.53.0 // indirect
|
||||
golang.org/x/sys v0.46.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/dokku/dokku/plugins/common => ../common
|
||||
55
plugins/plugin/go.sum
Normal file
55
plugins/plugin/go.sum
Normal file
@@ -0,0 +1,55 @@
|
||||
github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI=
|
||||
github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
|
||||
github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/melbahja/goph v1.5.1 h1:gdZyjn5nM6FO6mAZrv7XqE2gArQbb+V6FdIyH3Ru3vA=
|
||||
github.com/melbahja/goph v1.5.1/go.mod h1:dDwo+44cmvfDLdiVpc6fJxexf5BA5yEDUeE5YgtuDO4=
|
||||
github.com/onsi/gomega v1.42.1 h1:iN1rCUX+44NZ1Dc97MPoeFYbFR0vh8zxoxMFwKdyZ6I=
|
||||
github.com/onsi/gomega v1.42.1/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg=
|
||||
github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8=
|
||||
github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I=
|
||||
github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
|
||||
github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.10 h1:+5FbKNTe5Z9aspU88DPIKJ9z2KZoaGCu6Sr6kKR/5mU=
|
||||
github.com/pkg/sftp v1.13.10/go.mod h1:bJ1a7uDhrX/4OII+agvy28lzRvQrmIQuaHrcI1HbeGA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk=
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
|
||||
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
|
||||
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
||||
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
||||
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
|
||||
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
|
||||
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
|
||||
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
|
||||
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -31,7 +31,7 @@ fn-help-content() {
|
||||
plugin:enable <name>, Enable a previously disabled plugin
|
||||
plugin:install [--core|--git-url] [--committish branch|commit|commit] [--name custom-plugin-name] [--skip-install-trigger], Optionally download git-url (and pin to the specified branch/commit/tag) & run install trigger for active plugins (or only core ones)
|
||||
plugin:install-dependencies [--core], Run install-dependencies trigger for active plugins (or only core ones)
|
||||
plugin:list, Print active plugins
|
||||
plugin:list [--format stdout|json], Print active plugins
|
||||
plugin:trigger <args...>, Trigger an arbitrary plugin hook
|
||||
plugin:uninstall <name>, Uninstall a plugin (third-party only)
|
||||
plugin:update [name [branch|commit|tag]], Optionally update named plugin from git (and pin to the specified branch/commit/tag) & run update trigger for active plugins
|
||||
|
||||
@@ -8,6 +8,35 @@ cmd-plugin-list() {
|
||||
declare cmd="plugin"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
local FORMAT="stdout"
|
||||
local arg
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
arg="$1"
|
||||
shift
|
||||
case "$arg" in
|
||||
--format)
|
||||
if [[ "$#" -gt 0 ]]; then
|
||||
FORMAT="$1"
|
||||
shift
|
||||
else
|
||||
FORMAT=""
|
||||
fi
|
||||
;;
|
||||
--format=*)
|
||||
FORMAT="${arg#--format=}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$FORMAT" != "stdout" ]] && [[ "$FORMAT" != "json" ]]; then
|
||||
dokku_log_fail "Invalid output format specified, supported formats: json, stdout"
|
||||
fi
|
||||
|
||||
if [[ "$FORMAT" == "json" ]]; then
|
||||
"$PLUGIN_AVAILABLE_PATH/plugin/plugin-list" --format json
|
||||
return "$?"
|
||||
fi
|
||||
|
||||
plugn list
|
||||
}
|
||||
|
||||
|
||||
136
plugins/plugin/plugin.go
Normal file
136
plugins/plugin/plugin.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// PluginInfo describes an installed dokku plugin
|
||||
type PluginInfo struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Core bool `json:"core"`
|
||||
Description string `json:"description"`
|
||||
SourceURL string `json:"source_url"`
|
||||
Committish string `json:"committish"`
|
||||
Branch string `json:"branch"`
|
||||
}
|
||||
|
||||
// CommandList lists all installed plugins in the specified format
|
||||
func CommandList(format string) error {
|
||||
if format != "json" {
|
||||
return fmt.Errorf("Invalid output format specified, supported formats: json")
|
||||
}
|
||||
|
||||
plugins, err := listPlugins()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := json.Marshal(plugins)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
common.Log(string(out))
|
||||
return nil
|
||||
}
|
||||
|
||||
// listPlugins returns metadata for every installed plugin, enriched with git
|
||||
// source information for git-based third-party plugins
|
||||
func listPlugins() ([]PluginInfo, error) {
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "plugn",
|
||||
Args: []string{"list"},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
coreEnabledPath := common.MustGetEnv("PLUGIN_CORE_ENABLED_PATH")
|
||||
availablePath := common.MustGetEnv("PLUGIN_AVAILABLE_PATH")
|
||||
|
||||
plugins := parsePlugnList(result.StdoutContents())
|
||||
|
||||
errs := new(errgroup.Group)
|
||||
for i := range plugins {
|
||||
i := i
|
||||
errs.Go(func() error {
|
||||
plugins[i].Core = common.IsSymlink(filepath.Join(coreEnabledPath, plugins[i].Name))
|
||||
enrichGitSource(&plugins[i], availablePath)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if err := errs.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return plugins, nil
|
||||
}
|
||||
|
||||
// parsePlugnList parses the output of `plugn list` into plugin metadata. Each
|
||||
// data line is formatted as `<name> <version> <enabled|disabled> <description>`,
|
||||
// preceded by a `plugn: <treeish>` header line that is skipped.
|
||||
func parsePlugnList(output string) []PluginInfo {
|
||||
plugins := []PluginInfo{}
|
||||
for _, line := range strings.Split(output, "\n") {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 3 || fields[0] == "plugn:" {
|
||||
continue
|
||||
}
|
||||
|
||||
description := ""
|
||||
if len(fields) > 3 {
|
||||
description = strings.Join(fields[3:], " ")
|
||||
}
|
||||
|
||||
plugins = append(plugins, PluginInfo{
|
||||
Name: fields[0],
|
||||
Version: fields[1],
|
||||
Enabled: fields[2] == "enabled",
|
||||
Description: description,
|
||||
})
|
||||
}
|
||||
|
||||
return plugins
|
||||
}
|
||||
|
||||
// enrichGitSource populates the git source fields for a git-based plugin,
|
||||
// leaving them empty for core, tarball, or file-based installs
|
||||
func enrichGitSource(info *PluginInfo, availablePath string) {
|
||||
pluginDir := filepath.Join(availablePath, info.Name)
|
||||
if _, err := os.Stat(filepath.Join(pluginDir, ".git")); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
info.SourceURL = gitOutput(pluginDir, "remote", "get-url", "origin")
|
||||
info.Committish = gitOutput(pluginDir, "rev-parse", "HEAD")
|
||||
if branch := gitOutput(pluginDir, "rev-parse", "--abbrev-ref", "HEAD"); branch != "HEAD" {
|
||||
info.Branch = branch
|
||||
}
|
||||
}
|
||||
|
||||
// gitOutput runs a git command in the given directory and returns its trimmed
|
||||
// stdout, or an empty string on error. The directory is marked as safe so the
|
||||
// lookup works regardless of which user invokes plugin:list.
|
||||
func gitOutput(dir string, args ...string) string {
|
||||
gitArgs := append([]string{"-c", "safe.directory=" + dir}, args...)
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "git",
|
||||
Args: gitArgs,
|
||||
WorkingDirectory: dir,
|
||||
})
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return result.StdoutContents()
|
||||
}
|
||||
45
plugins/plugin/plugin_test.go
Normal file
45
plugins/plugin/plugin_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParsePlugnList(t *testing.T) {
|
||||
output := `plugn: dev
|
||||
00_dokku-standard 0.38.21 enabled dokku core standard plugin
|
||||
smoke-test-plugin 0.2.0 disabled a third party plugin
|
||||
bare-plugin 1.0.0 enabled`
|
||||
|
||||
plugins := parsePlugnList(output)
|
||||
if len(plugins) != 3 {
|
||||
t.Fatalf("expected 3 plugins, got %d", len(plugins))
|
||||
}
|
||||
|
||||
first := plugins[0]
|
||||
if first.Name != "00_dokku-standard" {
|
||||
t.Errorf("expected name 00_dokku-standard, got %q", first.Name)
|
||||
}
|
||||
if first.Version != "0.38.21" {
|
||||
t.Errorf("expected version 0.38.21, got %q", first.Version)
|
||||
}
|
||||
if !first.Enabled {
|
||||
t.Errorf("expected plugin to be enabled")
|
||||
}
|
||||
if first.Description != "dokku core standard plugin" {
|
||||
t.Errorf("expected multi-word description, got %q", first.Description)
|
||||
}
|
||||
|
||||
if plugins[1].Enabled {
|
||||
t.Errorf("expected smoke-test-plugin to be disabled")
|
||||
}
|
||||
if plugins[1].Description != "a third party plugin" {
|
||||
t.Errorf("expected multi-word description, got %q", plugins[1].Description)
|
||||
}
|
||||
|
||||
if plugins[2].Name != "bare-plugin" {
|
||||
t.Errorf("expected name bare-plugin, got %q", plugins[2].Name)
|
||||
}
|
||||
if plugins[2].Description != "" {
|
||||
t.Errorf("expected empty description, got %q", plugins[2].Description)
|
||||
}
|
||||
}
|
||||
20
plugins/plugin/src/plugin-list/plugin-list.go
Normal file
20
plugins/plugin/src/plugin-list/plugin-list.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/dokku/dokku/plugins/plugin"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func main() {
|
||||
args := flag.NewFlagSet("plugin:list", flag.ExitOnError)
|
||||
format := args.String("format", "json", "format: [ json ]")
|
||||
args.Parse(os.Args[1:])
|
||||
|
||||
if err := plugin.CommandList(*format); err != nil {
|
||||
common.LogFailWithError(err)
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,70 @@ teardown() {
|
||||
assert_output "$help_output"
|
||||
}
|
||||
|
||||
@test "(plugin) plugin:list --format json" {
|
||||
run /bin/bash -c "dokku plugin:list --format nonsense"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_failure
|
||||
assert_output_contains "Invalid output format"
|
||||
|
||||
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"apps\") | .core'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "true"
|
||||
|
||||
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"apps\") | .enabled'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "true"
|
||||
|
||||
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"apps\") | .source_url'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output ""
|
||||
|
||||
# Clone a git-based third-party plugin directly into the available path so the
|
||||
# git install source is present without running the (build-dependent) install
|
||||
# trigger. plugn lists it as a disabled plugin.
|
||||
run /bin/bash -c "git clone $TEST_PLUGIN_GIT_REPO $PLUGIN_AVAILABLE_PATH/$TEST_PLUGIN_NAME"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"$TEST_PLUGIN_NAME\") | .source_url'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "$TEST_PLUGIN_GIT_REPO"
|
||||
|
||||
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"$TEST_PLUGIN_NAME\") | .core'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "false"
|
||||
|
||||
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"$TEST_PLUGIN_NAME\") | .enabled'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "false"
|
||||
|
||||
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"$TEST_PLUGIN_NAME\") | .committish | length'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "40"
|
||||
|
||||
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"$TEST_PLUGIN_NAME\") | .branch'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output_exists
|
||||
}
|
||||
|
||||
@test "(plugin) plugin:install, plugin:disable, plugin:update plugin:uninstall" {
|
||||
run /bin/bash -c "dokku plugin:installed $TEST_PLUGIN_NAME"
|
||||
echo "output: $output"
|
||||
|
||||
Reference in New Issue
Block a user