Skip to content

Commit

Permalink
First approach to extensible shell with plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
marc-gr committed Aug 30, 2023
1 parent 3295997 commit bb6a0e7
Show file tree
Hide file tree
Showing 12 changed files with 621 additions and 1 deletion.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,12 @@ _Context: package_

Boot up the stack.

### `elastic-package shell`

_Context: global_



### `elastic-package stack`

_Context: global_
Expand Down
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ var commands = []*cobraext.Command{
setupPublishCommand(),
setupReportsCommand(),
setupServiceCommand(),
setupShellCommand(),
setupStackCommand(),
setupStatusCommand(),
setupTestCommand(),
Expand Down
29 changes: 29 additions & 0 deletions cmd/shell.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.

package cmd

import (
cshell "github.com/brianstrauch/cobra-shell"
"github.com/spf13/cobra"

"github.com/elastic/elastic-package/internal/cobraext"
"github.com/elastic/elastic-package/pkg/shell"
)

func setupShellCommand() *cobraext.Command {
cmd := &cobra.Command{
Use: "shell",
Hidden: true,
SilenceUsage: true,
}
cmd.CompletionOptions.DisableDefaultCmd = true
cmd.CompletionOptions.HiddenDefaultCmd = true

shell.AttachCommands(cmd)

shellCmd := cshell.New(cmd, nil)

return cobraext.NewCommand(shellCmd, cobraext.ContextGlobal)
}
7 changes: 6 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/ProtonMail/gopenpgp/v2 v2.7.3
github.com/aymerick/raymond v2.0.2+incompatible
github.com/boumenot/gocover-cobertura v1.2.0
github.com/brianstrauch/cobra-shell v0.4.0
github.com/cbroglie/mustache v1.4.0
github.com/cespare/xxhash/v2 v2.2.0
github.com/dustin/go-humanize v1.0.1
Expand All @@ -26,11 +27,13 @@ require (
github.com/google/uuid v1.3.1
github.com/jedib0t/go-pretty v4.3.0+incompatible
github.com/magefile/mage v1.15.0
github.com/mattn/go-sqlite3 v1.14.17
github.com/mholt/archiver/v3 v3.5.1
github.com/olekukonko/tablewriter v0.0.5
github.com/pmezard/go-difflib v1.0.0
github.com/shirou/gopsutil/v3 v3.23.7
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4
golang.org/x/tools v0.12.0
gopkg.in/yaml.v3 v3.0.1
Expand Down Expand Up @@ -58,6 +61,7 @@ require (
github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
github.com/c-bata/go-prompt v0.2.6 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/creasty/defaults v1.7.0 // indirect
Expand Down Expand Up @@ -109,6 +113,7 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mattn/go-tty v0.0.3 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
Expand All @@ -126,6 +131,7 @@ require (
github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/term v1.2.0-beta.2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/rivo/uniseg v0.4.3 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
Expand All @@ -134,7 +140,6 @@ require (
github.com/shopspring/decimal v1.3.1 // indirect
github.com/skeema/knownhosts v1.2.0 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
Expand Down
18 changes: 18 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,13 @@ github.com/aymerick/raymond v2.0.2+incompatible h1:VEp3GpgdAnv9B2GFyTvqgcKvY+mfK
github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/boumenot/gocover-cobertura v1.2.0 h1:g+VROIASoEHBrEilIyaCmgo7HGm+AV5yKEPLk0qIY+s=
github.com/boumenot/gocover-cobertura v1.2.0/go.mod h1:fz7ly8dslE42VRR5ZWLt2OHGDHjkTiA2oNvKgJEjLT0=
github.com/brianstrauch/cobra-shell v0.4.0 h1:oPWTBqPPbE8Vd/i3WRvQd8XWTrevIwR0bFBIS7X6gWk=
github.com/brianstrauch/cobra-shell v0.4.0/go.mod h1:QkRKnD1+MfpITTqYDE8Yp8zALgsHdeYur/qAw4kNr8c=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/cbroglie/mustache v1.4.0 h1:Azg0dVhxTml5me+7PsZ7WPrQq1Gkf3WApcHMjMprYoU=
github.com/cbroglie/mustache v1.4.0/go.mod h1:SS1FTIghy0sjse4DUVGV1k/40B1qE1XkD9DtDsHo9iM=
github.com/c-bata/go-prompt v0.2.6 h1:POP+nrHE+DfLYx370bedwNhsqmpCUynWPxuHi0C5vZI=
github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
Expand Down Expand Up @@ -257,19 +261,27 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI=
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
Expand Down Expand Up @@ -321,6 +333,8 @@ github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFz
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw=
github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
Expand Down Expand Up @@ -470,9 +484,13 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
6 changes: 6 additions & 0 deletions internal/configuration/locations/locations.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const (
stackDir = "stack"
packagesDir = "development"
profilesDir = "profiles"
pluginsDir = "shell_plugins"

temporaryDir = "tmp"
deployerDir = "deployer"
Expand Down Expand Up @@ -100,6 +101,11 @@ func (loc LocationManager) FieldsCacheDir() string {
return filepath.Join(loc.stackPath, fieldsCachedDir)
}

// ShellPluginsDir returns the directory where the shell plugins will be stored.
func (loc LocationManager) ShellPluginsDir() string {
return filepath.Join(loc.stackPath, pluginsDir)
}

// configurationDir returns the configuration directory location
// If a environment variable named as in elasticPackageDataHome is present,
// the value is used as is, overriding the value of this function.
Expand Down
13 changes: 13 additions & 0 deletions internal/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ func EnsureInstalled() error {
return fmt.Errorf("creating service logs directory failed: %w", err)
}

if err := createShellPluginsDir(elasticPackagePath); err != nil {
return fmt.Errorf("creating shell plugins directory failed: %w", err)
}

fmt.Fprintln(os.Stderr, "elastic-package has been installed.")
return nil
}
Expand Down Expand Up @@ -149,3 +153,12 @@ func createServiceLogsDir(elasticPackagePath *locations.LocationManager) error {
}
return nil
}

func createShellPluginsDir(elasticPackagePath *locations.LocationManager) error {
dirPath := elasticPackagePath.ShellPluginsDir()
err := os.MkdirAll(dirPath, 0755)
if err != nil {
return fmt.Errorf("mkdir failed (path: %s): %w", dirPath, err)
}
return nil
}
166 changes: 166 additions & 0 deletions pkg/shell/plugins/changelog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.

package main

import (
"context"
"errors"
"fmt"
"io"
"os"
"path/filepath"

"github.com/Masterminds/semver/v3"
"github.com/spf13/pflag"

"github.com/elastic/elastic-package/internal/cobraext"
"github.com/elastic/elastic-package/internal/packages"
"github.com/elastic/elastic-package/internal/packages/changelog"
"github.com/elastic/elastic-package/pkg/shell"
)

var _ shell.Command = changelogCmd{}

type changelogCmd struct{}

func (changelogCmd) Usage() string {
return "changelog --next {major|minor|patch} --description desc --type {bugfix|enhancement|breaking-change} --link link"
}

func (changelogCmd) Desc() string {
return "Add an entry to the changelog file in each of the packages in context 'Shell.Packages'."
}

func (changelogCmd) Flags() *pflag.FlagSet {
flags := pflag.NewFlagSet("", pflag.ContinueOnError)
flags.String(cobraext.ChangelogAddNextFlagName, "", cobraext.ChangelogAddNextFlagDescription)
flags.String(cobraext.ChangelogAddDescriptionFlagName, "", cobraext.ChangelogAddDescriptionFlagDescription)
flags.String(cobraext.ChangelogAddTypeFlagName, "", cobraext.ChangelogAddTypeFlagDescription)
flags.String(cobraext.ChangelogAddLinkFlagName, "", cobraext.ChangelogAddLinkFlagDescription)
return flags
}

func (changelogCmd) Exec(ctx context.Context, flags *pflag.FlagSet, args []string, _, stderr io.Writer) (context.Context, error) {
packages, ok := ctx.Value(ctxKeyPackages).([]string)
if !ok {
fmt.Fprintln(stderr, "no packages found in the context")
return ctx, nil
}
for _, pkg := range packages {
packageRoot := pkg
// check if we are in packages folder
if _, err := os.Stat(filepath.Join(".", pkg)); err != nil {
// check if we are in integrations root folder
packageRoot = filepath.Join(".", "packages", pkg)
if _, err := os.Stat(packageRoot); err != nil {
return ctx, errors.New("you need to be in intgerations root folder or in the packages folder")
}
}
if err := changelogAddCmdForRoot(packageRoot, flags, args); err != nil {
return ctx, err
}
}
return ctx, nil
}

func changelogAddCmdForRoot(packageRoot string, flags *pflag.FlagSet, args []string) error {
nextMode, _ := flags.GetString(cobraext.ChangelogAddNextFlagName)
v, err := changelogCmdVersion(nextMode, packageRoot)
if err != nil {
return err
}
version := v.String()

description, _ := flags.GetString(cobraext.ChangelogAddDescriptionFlagName)
changeType, _ := flags.GetString(cobraext.ChangelogAddTypeFlagName)
link, _ := flags.GetString(cobraext.ChangelogAddLinkFlagName)

entry := changelog.Revision{
Version: version,
Changes: []changelog.Entry{
{
Description: description,
Type: changeType,
Link: link,
},
},
}

if err := patchChangelogFile(packageRoot, entry); err != nil {
return err
}

if err := setManifestVersion(packageRoot, version); err != nil {
return err
}

return nil
}

func changelogCmdVersion(nextMode, packageRoot string) (*semver.Version, error) {
revisions, err := changelog.ReadChangelogFromPackageRoot(packageRoot)
if err != nil {
return nil, fmt.Errorf("failed to read current changelog: %w", err)
}
if len(revisions) == 0 {
return semver.MustParse("0.0.0"), nil
}

version, err := semver.NewVersion(revisions[0].Version)
if err != nil {
return nil, fmt.Errorf("invalid version in changelog %q: %w", revisions[0].Version, err)
}

switch nextMode {
case "":
break
case "major":
v := version.IncMajor()
version = &v
case "minor":
v := version.IncMinor()
version = &v
case "patch":
v := version.IncPatch()
version = &v
default:
return nil, fmt.Errorf("invalid value for %q: %s",
cobraext.ChangelogAddNextFlagName, nextMode)
}

return version, nil
}

// patchChangelogFile looks for the proper place to add the new revision in the changelog,
// trying to conserve original format and comments.
func patchChangelogFile(packageRoot string, patch changelog.Revision) error {
changelogPath := filepath.Join(packageRoot, changelog.PackageChangelogFile)
d, err := os.ReadFile(changelogPath)
if err != nil {
return err
}

d, err = changelog.PatchYAML(d, patch)
if err != nil {
return err
}

return os.WriteFile(changelogPath, d, 0644)
}

func setManifestVersion(packageRoot string, version string) error {
manifestPath := filepath.Join(packageRoot, packages.PackageManifestFile)
d, err := os.ReadFile(manifestPath)
if err != nil {
return err
}

d, err = changelog.SetManifestVersion(d, version)
if err != nil {
return err
}

return os.WriteFile(manifestPath, d, 0644)
}
Loading

0 comments on commit bb6a0e7

Please sign in to comment.