diff --git a/.github/workflows/package.yaml b/.github/workflows/package.yaml index af6ded5a44..378b2034d8 100644 --- a/.github/workflows/package.yaml +++ b/.github/workflows/package.yaml @@ -1,10 +1,8 @@ name: Package on: - push: - branches: - - tdstein/release + workflow_call: jobs: - release: + package: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -16,6 +14,4 @@ jobs: - run: just build - uses: actions/upload-artifact@v3 with: - path: | - bin/**/*.bin - bin/**/*.exe + path: bin/**/* diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index a7ef09766b..9eac2aaccd 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -650,7 +650,7 @@ jobs: - name: Make agents executable run: | - chmod -R +x ./bin/**/connect-client* + chmod -R +x ./bin/**/connect-client # these are required to run docker on amd64 and arm64 platforms - diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000000..cf2a279095 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,23 @@ +name: Release +on: + push: + branches: + - tdstein/release + tags: + - "v*.*.*" +jobs: + package: + uses: ./.github/workflows/package.yaml + release: + runs-on: ubuntu-latest + needs: + - package + steps: + - uses: actions/download-artifact@v3 + with: + path: bin + - name: Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + files: bin diff --git a/build/package/Dockerfile b/build/package/Dockerfile index b22453663a..0b9a6cfc5c 100644 --- a/build/package/Dockerfile +++ b/build/package/Dockerfile @@ -3,6 +3,7 @@ FROM rockylinux:8 RUN dnf -y update\ && dnf -y install\ curl\ + git\ tar\ && dnf -y module enable nodejs:18\ && dnf -y module install nodejs:18 @@ -19,3 +20,5 @@ ENV PATH="$PATH:/usr/local/go/bin" RUN go env -w GOBIN=/usr/local/go/bin\ && go install honnef.co/go/tools/cmd/staticcheck@latest + +RUN git config --global --add safe.directory '*' diff --git a/cmd/connect-client/commands/publish.go b/cmd/connect-client/commands/publish.go index 8b015e105d..d1d99b29b8 100644 --- a/cmd/connect-client/commands/publish.go +++ b/cmd/connect-client/commands/publish.go @@ -216,7 +216,8 @@ func (cmd *CreateBundleCmd) Run(args *cli_types.CommonArgs, ctx *cli_types.CLICo if err != nil { return err } - return publish.CreateBundleFromDirectory(&cmd.PublishArgs, cmd.BundleFile, ctx.Logger) + publisher := publish.New(&cmd.PublishArgs) + return publisher.CreateBundleFromDirectory(cmd.BundleFile, ctx.Logger) } type WriteManifestCmd struct { @@ -228,7 +229,8 @@ func (cmd *WriteManifestCmd) Run(args *cli_types.CommonArgs, ctx *cli_types.CLIC if err != nil { return err } - return publish.WriteManifestFromDirectory(&cmd.PublishArgs, ctx.Logger) + publisher := publish.New(&cmd.PublishArgs) + return publisher.WriteManifestFromDirectory(ctx.Logger) } type PublishCmd struct { @@ -240,7 +242,8 @@ func (cmd *PublishCmd) Run(args *cli_types.CommonArgs, ctx *cli_types.CLIContext if err != nil { return err } - return publish.PublishDirectory(&cmd.PublishArgs, ctx.Accounts, ctx.Logger) + publisher := publish.New(&cmd.PublishArgs) + return publisher.PublishDirectory(ctx.Accounts, ctx.Logger) } type PublishUICmd struct { diff --git a/go.mod b/go.mod index afd0f5c5f0..1881d1f8c3 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/alecthomas/kong v0.7.1 github.com/chmike/securecookie v1.3.4 github.com/gobwas/glob v0.2.3 + github.com/gorilla/mux v1.8.0 github.com/iriri/minimal/gitignore v0.3.2 github.com/mitchellh/mapstructure v1.5.0 github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 @@ -17,7 +18,6 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/gorilla/mux v1.8.0 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.8.0 // indirect diff --git a/internal/publish/publish.go b/internal/publish/publish.go index afa2e19081..bf3efddede 100644 --- a/internal/publish/publish.go +++ b/internal/publish/publish.go @@ -21,13 +21,23 @@ import ( "github.com/rstudio/connect-client/internal/util" ) -func CreateBundleFromDirectory(cmd *cli_types.PublishArgs, dest util.Path, log logging.Logger) error { +type Publisher struct { + args *cli_types.PublishArgs +} + +func New(args *cli_types.PublishArgs) *Publisher { + return &Publisher{ + args: args, + } +} + +func (p *Publisher) CreateBundleFromDirectory(dest util.Path, log logging.Logger) error { bundleFile, err := dest.Create() if err != nil { return err } defer bundleFile.Close() - bundler, err := bundles.NewBundler(cmd.State.SourceDir, &cmd.State.Manifest, cmd.Exclude, nil, log) + bundler, err := bundles.NewBundler(p.args.State.SourceDir, &p.args.State.Manifest, p.args.Exclude, nil, log) if err != nil { return err } @@ -35,8 +45,8 @@ func CreateBundleFromDirectory(cmd *cli_types.PublishArgs, dest util.Path, log l return err } -func WriteManifestFromDirectory(cmd *cli_types.PublishArgs, log logging.Logger) error { - bundler, err := bundles.NewBundler(cmd.State.SourceDir, &cmd.State.Manifest, cmd.Exclude, nil, log) +func (p *Publisher) WriteManifestFromDirectory(log logging.Logger) error { + bundler, err := bundles.NewBundler(p.args.State.SourceDir, &p.args.State.Manifest, p.args.Exclude, nil, log) if err != nil { return err } @@ -44,7 +54,7 @@ func WriteManifestFromDirectory(cmd *cli_types.PublishArgs, log logging.Logger) if err != nil { return err } - manifestPath := cmd.State.SourceDir.Join(bundles.ManifestFilename) + manifestPath := p.args.State.SourceDir.Join(bundles.ManifestFilename) log.Info("Writing manifest", "path", manifestPath) manifestJSON, err := manifest.ToJSON() if err != nil { @@ -62,7 +72,7 @@ type appInfo struct { DirectURL string `json:"direct-url"` } -func logAppInfo(accountURL string, contentID types.ContentID, log logging.Logger) error { +func (p *Publisher) logAppInfo(accountURL string, contentID types.ContentID, log logging.Logger) error { appInfo := appInfo{ DashboardURL: fmt.Sprintf("%s/connect/#/apps/%s", accountURL, contentID), DirectURL: fmt.Sprintf("%s/content/%s", accountURL, contentID), @@ -82,25 +92,29 @@ func logAppInfo(accountURL string, contentID types.ContentID, log logging.Logger return err } -func PublishManifestFiles(cmd *cli_types.PublishArgs, lister accounts.AccountList, log logging.Logger) error { - bundler, err := bundles.NewBundlerForManifest(cmd.State.SourceDir, &cmd.State.Manifest, log) +func (p *Publisher) PublishManifestFiles(lister accounts.AccountList, log logging.Logger) error { + bundler, err := bundles.NewBundlerForManifest(p.args.State.SourceDir, &p.args.State.Manifest, log) if err != nil { return err } - return publish(cmd, bundler, lister, log) + return p.publish(bundler, lister, log) } -func PublishDirectory(cmd *cli_types.PublishArgs, lister accounts.AccountList, log logging.Logger) error { - log.Info("Publishing from directory", "path", cmd.State.SourceDir) - bundler, err := bundles.NewBundler(cmd.State.SourceDir, &cmd.State.Manifest, cmd.Exclude, nil, log) +func (p *Publisher) PublishDirectory(lister accounts.AccountList, log logging.Logger) error { + log.Info("Publishing from directory", "path", p.args.State.SourceDir) + bundler, err := bundles.NewBundler(p.args.State.SourceDir, &p.args.State.Manifest, p.args.Exclude, nil, log) if err != nil { return err } - return publish(cmd, bundler, lister, log) + return p.publish(bundler, lister, log) } -func publish(cmd *cli_types.PublishArgs, bundler bundles.Bundler, lister accounts.AccountList, log logging.Logger) error { - account, err := lister.GetAccountByName(cmd.State.Target.AccountName) +func (p *Publisher) publish( + bundler bundles.Bundler, + lister accounts.AccountList, + log logging.Logger) error { + + account, err := lister.GetAccountByName(p.args.State.Target.AccountName) if err != nil { return err } @@ -110,7 +124,7 @@ func publish(cmd *cli_types.PublishArgs, bundler bundles.Bundler, lister account if err != nil { return err } - err = publishWithClient(cmd, bundler, account, client, log) + err = p.publishWithClient(bundler, account, client, log) if err != nil { log.Failure(err) } @@ -121,7 +135,13 @@ type DeploymentNotFoundDetails struct { ContentID types.ContentID } -func withLog[T any](op events.Operation, msg string, label string, log logging.Logger, fn func() (T, error)) (value T, err error) { +func withLog[T any]( + op events.Operation, + msg string, + label string, + log logging.Logger, + fn func() (T, error)) (value T, err error) { + log = log.WithArgs(logging.LogKeyOp, op) log.Start(msg) value, err = fn() @@ -135,7 +155,12 @@ func withLog[T any](op events.Operation, msg string, label string, log logging.L return value, nil } -func publishWithClient(cmd *cli_types.PublishArgs, bundler bundles.Bundler, account *accounts.Account, client clients.APIClient, log logging.Logger) error { +func (p *Publisher) publishWithClient( + bundler bundles.Bundler, + account *accounts.Account, + client clients.APIClient, + log logging.Logger) error { + log.Start("Starting deployment to server", logging.LogKeyOp, events.PublishOp, "server", account.URL, @@ -160,10 +185,10 @@ func publishWithClient(cmd *cli_types.PublishArgs, bundler bundles.Bundler, acco } var contentID types.ContentID - if cmd.State.Target.ContentId != "" && !cmd.New { - contentID = cmd.State.Target.ContentId + if p.args.State.Target.ContentId != "" && !p.args.New { + contentID = p.args.State.Target.ContentId _, err := withLog(events.PublishCreateDeploymentOp, "Updating deployment", "content_id", log, func() (any, error) { - return contentID, client.UpdateDeployment(contentID, cmd.State.Connect.Content) + return contentID, client.UpdateDeployment(contentID, p.args.State.Connect.Content) }) if err != nil { httpErr, ok := err.(*clients.HTTPError) @@ -177,7 +202,7 @@ func publishWithClient(cmd *cli_types.PublishArgs, bundler bundles.Bundler, acco } } else { contentID, err = withLog(events.PublishCreateDeploymentOp, "Creating deployment", "content_id", log, func() (types.ContentID, error) { - return client.CreateDeployment(cmd.State.Connect.Content) + return client.CreateDeployment(p.args.State.Connect.Content) }) if err != nil { return err @@ -192,7 +217,7 @@ func publishWithClient(cmd *cli_types.PublishArgs, bundler bundles.Bundler, acco return err } - cmd.State.Target = state.TargetID{ + p.args.State.Target = state.TargetID{ ServerType: account.ServerType, AccountName: account.Name, ServerURL: account.URL, @@ -210,11 +235,11 @@ func publishWithClient(cmd *cli_types.PublishArgs, bundler bundles.Bundler, acco return err } - taskLogger := log.WithArgs("source", "serverLog") + taskLogger := log.WithArgs("source", "serverp.log") err = client.WaitForTask(taskID, taskLogger) if err != nil { return err } log = log.WithArgs(logging.LogKeyOp, events.AgentOp) - return logAppInfo(account.URL, contentID, log) + return p.logAppInfo(account.URL, contentID, log) } diff --git a/internal/publish/publish_test.go b/internal/publish/publish_test.go index 0bfed1024d..8752bcc73f 100644 --- a/internal/publish/publish_test.go +++ b/internal/publish/publish_test.go @@ -54,7 +54,8 @@ func (s *PublishSuite) TestCreateBundle() { State: state.NewDeployment(), } cmd.State.SourceDir = s.cwd - err := CreateBundleFromDirectory(cmd, dest, s.log) + publisher := New(cmd) + err := publisher.CreateBundleFromDirectory(dest, s.log) s.NoError(err) s.True(dest.Exists()) } @@ -70,7 +71,8 @@ func (s *PublishSuite) TestCreateBundleFailCreate() { State: state.NewDeployment(), } cmd.State.SourceDir = s.cwd - err := CreateBundleFromDirectory(cmd, dest, s.log) + publisher := New(cmd) + err := publisher.CreateBundleFromDirectory(dest, s.log) s.ErrorIs(err, testError) } @@ -83,7 +85,8 @@ func (s *PublishSuite) TestWriteManifest() { } cmd.State.SourceDir = s.cwd - err := WriteManifestFromDirectory(cmd, s.log) + publisher := New(cmd) + err := publisher.WriteManifestFromDirectory(s.log) s.NoError(err) s.True(manifestPath.Exists()) @@ -143,7 +146,9 @@ func (s *PublishSuite) publishWithClient(createErr, uploadErr, deployErr, waitEr client.On("UploadBundle", myContentID, mock.Anything).Return(myBundleID, uploadErr) client.On("DeployBundle", myContentID, myBundleID).Return(myTaskID, deployErr) client.On("WaitForTask", myTaskID, mock.Anything).Return(waitErr) - err = publishWithClient(cmd, bundler, account, client, s.log) + + publisher := New(cmd) + err = publisher.publishWithClient(bundler, account, client, s.log) if expectedErr == nil { s.NoError(err) } else { diff --git a/internal/services/api/post_publish.go b/internal/services/api/post_publish.go new file mode 100644 index 0000000000..cfc8acbc8c --- /dev/null +++ b/internal/services/api/post_publish.go @@ -0,0 +1,46 @@ +package api + +// Copyright (C) 2023 by Posit Software, PBC. + +import ( + "encoding/json" + "net/http" + + "github.com/rstudio/connect-client/internal/accounts" + "github.com/rstudio/connect-client/internal/cli_types" + "github.com/rstudio/connect-client/internal/logging" + "github.com/rstudio/connect-client/internal/state" +) + +type PublishReponse struct { + LocalID state.LocalDeploymentID `json:"local_id"` // Unique ID of this publishing operation. Only valid for this run of the agent. +} + +type ManifestFilesPublisher interface { + PublishManifestFiles(lister accounts.AccountList, log logging.Logger) error +} + +func PostPublishHandlerFunc(publisher ManifestFilesPublisher, publishArgs *cli_types.PublishArgs, lister accounts.AccountList, log logging.Logger) http.HandlerFunc { + return func(w http.ResponseWriter, req *http.Request) { + localID, err := state.NewLocalID() + if err != nil { + InternalError(w, req, log, err) + return + } + publishArgs.State.LocalID = localID + response := PublishReponse{ + LocalID: localID, + } + w.Header().Set("content-type", "application/json") + w.WriteHeader(http.StatusAccepted) + json.NewEncoder(w).Encode(response) + + go func() { + log = log.WithArgs("local_id", localID) + err := publisher.PublishManifestFiles(lister, log) + if err != nil { + log.Error("Deployment failed", "error", err.Error()) + } + }() + } +} diff --git a/internal/services/api/post_publish_test.go b/internal/services/api/post_publish_test.go new file mode 100644 index 0000000000..04b50f11b0 --- /dev/null +++ b/internal/services/api/post_publish_test.go @@ -0,0 +1,70 @@ +package api + +// Copyright (C) 2023 by Posit Software, PBC. + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/rstudio/connect-client/internal/accounts" + "github.com/rstudio/connect-client/internal/cli_types" + "github.com/rstudio/connect-client/internal/logging" + "github.com/rstudio/connect-client/internal/state" + "github.com/rstudio/connect-client/internal/util/utiltest" + "github.com/stretchr/testify/suite" +) + +type PublishHandlerFuncSuite struct { + utiltest.Suite +} + +func TestPublishHandlerFuncSuite(t *testing.T) { + suite.Run(t, new(PublishHandlerFuncSuite)) +} + +type mockPublisher struct { + suite *PublishHandlerFuncSuite + args *cli_types.PublishArgs +} + +func (m *mockPublisher) PublishManifestFiles(lister accounts.AccountList, log logging.Logger) error { + m.suite.NotNil(m.args) + m.suite.NotNil(lister) + m.suite.NotNil(log) + m.suite.NotEqual(state.LocalDeploymentID(""), m.args.State.LocalID) + return nil +} + +func (s *PublishHandlerFuncSuite) TestPublishHandlerFunc() { + publishArgs := &cli_types.PublishArgs{ + State: state.NewDeployment(), + } + oldID := publishArgs.State.LocalID + log := logging.New() + + rec := httptest.NewRecorder() + req, err := http.NewRequest("POST", "/api/publish", nil) + s.NoError(err) + + publisher := &mockPublisher{ + suite: s, + args: publishArgs, + } + lister := &accounts.MockAccountList{} + handler := PostPublishHandlerFunc(publisher, publishArgs, lister, log) + handler(rec, req) + + s.Equal(http.StatusAccepted, rec.Result().StatusCode) + s.Equal("application/json", rec.Header().Get("content-type")) + + res := &PublishReponse{} + dec := json.NewDecoder(rec.Body) + dec.DisallowUnknownFields() + s.NoError(dec.Decode(res)) + + s.NotEqual(state.LocalDeploymentID(""), publishArgs.State.LocalID) + s.NotEqual(oldID, publishArgs.State.LocalID) + s.Equal(publishArgs.State.LocalID, res.LocalID) +} diff --git a/internal/services/api/publish.go b/internal/services/api/publish.go deleted file mode 100644 index 126cbce3a9..0000000000 --- a/internal/services/api/publish.go +++ /dev/null @@ -1,26 +0,0 @@ -package api - -// Copyright (C) 2023 by Posit Software, PBC. - -import ( - "net/http" - - "github.com/rstudio/connect-client/internal/accounts" - "github.com/rstudio/connect-client/internal/cli_types" - "github.com/rstudio/connect-client/internal/logging" - "github.com/rstudio/connect-client/internal/publish" -) - -func PostPublishHandlerFunc(publishArgs *cli_types.PublishArgs, lister accounts.AccountList, log logging.Logger) http.HandlerFunc { - return func(w http.ResponseWriter, req *http.Request) { - switch req.Method { - case http.MethodPost: - err := publish.PublishManifestFiles(publishArgs, lister, log) - if err != nil { - InternalError(w, req, log, err) - } - default: - return - } - } -} diff --git a/internal/services/local_token.go b/internal/services/local_token.go index 3e00f11858..90ae6a0eaa 100644 --- a/internal/services/local_token.go +++ b/internal/services/local_token.go @@ -3,32 +3,15 @@ package services // Copyright (C) 2023 by Posit Software, PBC. import ( - "encoding/base64" - "strings" - "github.com/rstudio/connect-client/internal/util" ) type LocalToken string func NewLocalToken() (LocalToken, error) { - key, err := util.RandomBytes(32) - if err != nil { - return LocalToken(""), err - } - tokenString, err := toBase64(key) + str, err := util.RandomString(32) if err != nil { return LocalToken(""), err } - return LocalToken(tokenString), nil -} - -func toBase64(data []byte) (string, error) { - var writer strings.Builder - encoder := base64.NewEncoder(base64.RawURLEncoding, &writer) - _, err := encoder.Write(data) - if err != nil { - return "", err - } - return writer.String(), nil + return LocalToken(str), nil } diff --git a/internal/services/local_token_test.go b/internal/services/local_token_test.go new file mode 100644 index 0000000000..5575925704 --- /dev/null +++ b/internal/services/local_token_test.go @@ -0,0 +1,26 @@ +package services + +// Copyright (C) 2023 by Posit Software, PBC. + +import ( + "testing" + + "github.com/rstudio/connect-client/internal/util/utiltest" + "github.com/stretchr/testify/suite" +) + +type LocalTokenSuite struct { + utiltest.Suite +} + +func TestLocalTokenSuite(t *testing.T) { + suite.Run(t, new(LocalTokenSuite)) +} + +func (s *LocalTokenSuite) TestNewLocalToken() { + token1, err := NewLocalToken() + s.NoError(err) + token2, err := NewLocalToken() + s.NoError(err) + s.NotEqual(token1, token2) +} diff --git a/internal/services/ui/ui_service.go b/internal/services/ui/ui_service.go index 55f636fdff..522318a577 100644 --- a/internal/services/ui/ui_service.go +++ b/internal/services/ui/ui_service.go @@ -9,6 +9,7 @@ import ( "github.com/rstudio/connect-client/internal/accounts" "github.com/rstudio/connect-client/internal/cli_types" "github.com/rstudio/connect-client/internal/logging" + "github.com/rstudio/connect-client/internal/publish" "github.com/rstudio/connect-client/internal/services" "github.com/rstudio/connect-client/internal/services/api" "github.com/rstudio/connect-client/internal/services/api/deployments" @@ -81,7 +82,8 @@ func RouterHandlerFunc(afs afero.Fs, publishArgs *cli_types.PublishArgs, lister Methods(http.MethodPut) // POST /api/publish - r.Handle(ToPath("publish"), api.PostPublishHandlerFunc(publishArgs, lister, log)). + publisher := publish.New(publishArgs) + r.Handle(ToPath("publish"), api.PostPublishHandlerFunc(publisher, publishArgs, lister, log)). Methods(http.MethodPost) // GET / diff --git a/internal/state/deployment.go b/internal/state/deployment.go index 3eea9c204a..db18d6cf25 100644 --- a/internal/state/deployment.go +++ b/internal/state/deployment.go @@ -23,7 +23,18 @@ type TargetID struct { DeployedAt types.NullTime `json:"deployed_at" kong:"-"` // Date/time bundle was deployed } +type LocalDeploymentID string + +func NewLocalID() (LocalDeploymentID, error) { + str, err := util.RandomString(16) + if err != nil { + return LocalDeploymentID(""), err + } + return LocalDeploymentID(str), nil +} + type Deployment struct { + LocalID LocalDeploymentID `json:"local_id" kong:"-"` // Unique ID of this publishing operation. Only valid for this run of the agent. SourceDir util.Path `json:"source_path" kong:"-"` // Absolute path to source directory being published Target TargetID `json:"target" kong:"embed"` // Identity of previous deployment Manifest bundles.Manifest `json:"manifest" kong:"embed"` // manifest.json content for this deployment diff --git a/internal/util/random.go b/internal/util/random.go index 1b00214013..70c447b96f 100644 --- a/internal/util/random.go +++ b/internal/util/random.go @@ -4,6 +4,8 @@ package util import ( "crypto/rand" + "encoding/base64" + "strings" ) func RandomBytes(n int) ([]byte, error) { @@ -11,3 +13,26 @@ func RandomBytes(n int) ([]byte, error) { _, err := rand.Read(buf) return buf, err } + +func RandomString(n int) (string, error) { + // Base64 encoding of bytes->string expands length by 1/3 + key, err := RandomBytes((n * 3) / 4) + if err != nil { + return "", err + } + tokenString, err := toBase64(key) + if err != nil { + return "", err + } + return tokenString, nil +} + +func toBase64(data []byte) (string, error) { + var writer strings.Builder + encoder := base64.NewEncoder(base64.RawURLEncoding, &writer) + _, err := encoder.Write(data) + if err != nil { + return "", err + } + return writer.String(), nil +} diff --git a/internal/util/random_test.go b/internal/util/random_test.go index 330fc33d11..6ae6d87376 100644 --- a/internal/util/random_test.go +++ b/internal/util/random_test.go @@ -18,7 +18,31 @@ func TestRandomSuite(t *testing.T) { } func (s *RandomSuite) TestRandomBytes() { - r, err := RandomBytes(32) - s.Nil(err) - s.Len(r, 32) + r1, err := RandomBytes(32) + s.NoError(err) + s.Len(r1, 32) + + r2, err := RandomBytes(32) + s.NoError(err) + s.Len(r2, 32) + s.NotEqual(r1, r2) + + r3, err := RandomBytes(12) + s.NoError(err) + s.Len(r3, 12) +} + +func (s *RandomSuite) TestRandomString() { + r1, err := RandomString(32) + s.NoError(err) + s.Len(r1, 32) + + r2, err := RandomString(32) + s.NoError(err) + s.Len(r2, 32) + s.NotEqual(r1, r2) + + r3, err := RandomString(12) + s.NoError(err) + s.Len(r3, 12) } diff --git a/scripts/build.bash b/scripts/build.bash index dddf64c319..612c3771ac 100755 --- a/scripts/build.bash +++ b/scripts/build.bash @@ -1,14 +1,16 @@ #!/usr/bin/env bash +set -euo pipefail -set -e +CI="${CI:-false}" package=$1 -version=$2 -if [[ -z "$package" || -z "$version" ]]; then - echo "usage: $0 " +if [[ -z "$package" ]]; then + echo "usage: $0 " exit 1 fi echo "Package: $package" + +version=$(./scripts/get-version.bash) echo "Version: $version" name=$(basename "$package") @@ -57,11 +59,9 @@ do GOOS=${platform_split[0]} GOARCH=${platform_split[1]} - executable=./bin/$GOOS-$GOARCH/$name-$version + executable=./bin/$GOOS/$GOARCH/$name-$version if [ "$GOOS" = "windows" ]; then executable+='.exe' - else - executable+='.bin' fi if [ ! -d "./web/dist" ]; then diff --git a/scripts/fmt-check.bash b/scripts/fmt-check.bash index 3996d468c9..920adf047c 100755 --- a/scripts/fmt-check.bash +++ b/scripts/fmt-check.bash @@ -1,4 +1,5 @@ #!/usr/bin/env bash +set -euo pipefail # Use gofmt to check for fmt compliance. When there are formatting problems, # print the suggestions and exit with an error. diff --git a/scripts/get-version.bash b/scripts/get-version.bash index b947571895..9069fc15b8 100755 --- a/scripts/get-version.bash +++ b/scripts/get-version.bash @@ -1,6 +1,4 @@ #!/usr/bin/env bash +set -euo pipefail -docker pull -q ghcr.io/choffmeister/git-describe-semver:latest > /dev/null -docker run --rm -v $PWD:/workdir ghcr.io/choffmeister/git-describe-semver:latest \ - -drop-prefix \ - --fallback v0.0.0 +git describe --tags | sed 's/\v\(.*\).*/\1/' diff --git a/web/package-lock.json b/web/package-lock.json index 793de1e94a..c06e67cc2b 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -17,15 +17,18 @@ "vue": "^3.3.4" }, "devDependencies": { + "@pinia/testing": "^0.1.3", "@quasar/vite-plugin": "^1.4.1", "@types/node": "^20.5.4", "@typescript-eslint/eslint-plugin": "^6.4.1", "@typescript-eslint/parser": "^6.4.1", "@vitejs/plugin-vue": "^4.2.3", + "@vue/test-utils": "^2.4.1", "cypress": "^13.0.0", "eslint": "^8.47.0", "eslint-plugin-cypress": "^2.14.0", "eslint-plugin-vue": "^9.17.0", + "jsdom": "^22.1.0", "sass": "^1.66.1", "start-server-and-test": "^2.0.0", "typescript": "^5.0.2", @@ -634,6 +637,53 @@ "node": ">= 8" } }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true + }, + "node_modules/@pinia/testing": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@pinia/testing/-/testing-0.1.3.tgz", + "integrity": "sha512-D2Ds2s69kKFaRf2KCcP1NhNZEg5+we59aRyQalwRm7ygWfLM25nDH66267U3hNvRUOTx8ofL24GzodZkOmB5xw==", + "dev": true, + "dependencies": { + "vue-demi": ">=0.14.5" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "pinia": ">=2.1.5" + } + }, + "node_modules/@pinia/testing/node_modules/vue-demi": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "dev": true, + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/@quasar/extras": { "version": "1.16.6", "resolved": "https://registry.npmjs.org/@quasar/extras/-/extras-1.16.6.tgz", @@ -689,6 +739,15 @@ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/@types/chai": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", @@ -1223,6 +1282,25 @@ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz", "integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==" }, + "node_modules/@vue/test-utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.1.tgz", + "integrity": "sha512-VO8nragneNzUZUah6kOjiFmD/gwRjUauG9DROh6oaOeFwX1cZRUNHhdeogE8635cISigXFTtGLUQWx5KCb0xeg==", + "dev": true, + "dependencies": { + "js-beautify": "1.14.9", + "vue-component-type-helpers": "1.8.4" + }, + "peerDependencies": { + "@vue/server-renderer": "^3.0.1", + "vue": "^3.0.1" + }, + "peerDependenciesMeta": { + "@vue/server-renderer": { + "optional": true + } + } + }, "node_modules/@vue/typescript": { "version": "1.8.8", "resolved": "https://registry.npmjs.org/@vue/typescript/-/typescript-1.8.8.tgz", @@ -1233,6 +1311,18 @@ "@vue/language-core": "1.8.8" } }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "node_modules/acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", @@ -1263,6 +1353,18 @@ "node": ">=0.4.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -1907,6 +2009,22 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/config-chain/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -1939,6 +2057,18 @@ "node": ">=4" } }, + "node_modules/cssstyle": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "dev": true, + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", @@ -2026,6 +2156,20 @@ "node": ">=0.10" } }, + "node_modules/data-urls": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", + "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/dayjs": { "version": "1.11.9", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", @@ -2105,6 +2249,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, "node_modules/deep-eql": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", @@ -2164,6 +2314,18 @@ "node": ">=6.0.0" } }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "dev": true, + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -2180,6 +2342,57 @@ "safer-buffer": "^2.1.0" } }, + "node_modules/editorconfig": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "dev": true, + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/editorconfig/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -2208,6 +2421,18 @@ "node": ">=8.6" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/esbuild": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", @@ -2980,6 +3205,32 @@ "he": "bin/he" } }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/http-signature": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", @@ -2994,6 +3245,19 @@ "node": ">=0.10" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/human-signals": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", @@ -3003,6 +3267,18 @@ "node": ">=8.12.0" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -3185,6 +3461,12 @@ "node": ">=8" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -3240,6 +3522,66 @@ "@sideway/pinpoint": "^2.0.0" } }, + "node_modules/js-beautify": { + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.9.tgz", + "integrity": "sha512-coM7xq1syLcMyuVGyToxcj2AlzhkDjmfklL8r0JgJ7A76wyGMpJ1oA35mr4APdYNO/o/4YY8H54NQIJzhMbhBg==", + "dev": true, + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.3", + "glob": "^8.1.0", + "nopt": "^6.0.0" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/js-beautify/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/js-beautify/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-beautify/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -3258,6 +3600,48 @@ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, + "node_modules/jsdom": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", + "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "cssstyle": "^3.0.0", + "data-urls": "^4.0.0", + "decimal.js": "^10.4.3", + "domexception": "^4.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.4", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -3662,6 +4046,21 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -3695,6 +4094,12 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "dev": true + }, "node_modules/object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", @@ -3808,6 +4213,18 @@ "node": ">=6" } }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -4063,6 +4480,12 @@ "node": ">= 0.6.0" } }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -4276,6 +4699,12 @@ "fsevents": "~2.3.2" } }, + "node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -4351,6 +4780,18 @@ "node": ">=14.0.0" } }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -4644,6 +5085,12 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4731,7 +5178,19 @@ "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true, "engines": { - "node": ">= 4.0.0" + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" } }, "node_modules/ts-api-utils": { @@ -5054,6 +5513,12 @@ "@vue/shared": "3.3.4" } }, + "node_modules/vue-component-type-helpers": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-1.8.4.tgz", + "integrity": "sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==", + "dev": true + }, "node_modules/vue-eslint-parser": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz", @@ -5105,6 +5570,18 @@ "typescript": "*" } }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/wait-on": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.0.1.tgz", @@ -5134,6 +5611,49 @@ "form-data": "^4.0.0" } }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", + "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "dev": true, + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5188,6 +5708,27 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", @@ -5197,6 +5738,12 @@ "node": ">=12" } }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -5575,6 +6122,30 @@ "fastq": "^1.6.0" } }, + "@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true + }, + "@pinia/testing": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@pinia/testing/-/testing-0.1.3.tgz", + "integrity": "sha512-D2Ds2s69kKFaRf2KCcP1NhNZEg5+we59aRyQalwRm7ygWfLM25nDH66267U3hNvRUOTx8ofL24GzodZkOmB5xw==", + "dev": true, + "requires": { + "vue-demi": ">=0.14.5" + }, + "dependencies": { + "vue-demi": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "dev": true, + "requires": {} + } + } + }, "@quasar/extras": { "version": "1.16.6", "resolved": "https://registry.npmjs.org/@quasar/extras/-/extras-1.16.6.tgz", @@ -5614,6 +6185,12 @@ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true + }, "@types/chai": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", @@ -6013,6 +6590,16 @@ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz", "integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==" }, + "@vue/test-utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.1.tgz", + "integrity": "sha512-VO8nragneNzUZUah6kOjiFmD/gwRjUauG9DROh6oaOeFwX1cZRUNHhdeogE8635cISigXFTtGLUQWx5KCb0xeg==", + "dev": true, + "requires": { + "js-beautify": "1.14.9", + "vue-component-type-helpers": "1.8.4" + } + }, "@vue/typescript": { "version": "1.8.8", "resolved": "https://registry.npmjs.org/@vue/typescript/-/typescript-1.8.8.tgz", @@ -6023,6 +6610,18 @@ "@vue/language-core": "1.8.8" } }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", @@ -6042,6 +6641,15 @@ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -6495,6 +7103,24 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + }, + "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + } + } + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -6518,6 +7144,15 @@ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true }, + "cssstyle": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "dev": true, + "requires": { + "rrweb-cssom": "^0.6.0" + } + }, "csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", @@ -6597,6 +7232,17 @@ "assert-plus": "^1.0.0" } }, + "data-urls": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", + "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "dev": true, + "requires": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.0" + } + }, "dayjs": { "version": "1.11.9", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", @@ -6646,6 +7292,12 @@ } } }, + "decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, "deep-eql": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", @@ -6690,6 +7342,15 @@ "esutils": "^2.0.2" } }, + "domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "dev": true, + "requires": { + "webidl-conversions": "^7.0.0" + } + }, "duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -6706,6 +7367,44 @@ "safer-buffer": "^2.1.0" } }, + "editorconfig": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "dev": true, + "requires": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true + }, + "minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -6731,6 +7430,12 @@ "strip-ansi": "^6.0.1" } }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true + }, "esbuild": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", @@ -7302,6 +8007,26 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "requires": { + "whatwg-encoding": "^2.0.0" + } + }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, "http-signature": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", @@ -7313,12 +8038,31 @@ "sshpk": "^1.14.1" } }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, "human-signals": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -7442,6 +8186,12 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -7485,6 +8235,51 @@ "@sideway/pinpoint": "^2.0.0" } }, + "js-beautify": { + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.9.tgz", + "integrity": "sha512-coM7xq1syLcMyuVGyToxcj2AlzhkDjmfklL8r0JgJ7A76wyGMpJ1oA35mr4APdYNO/o/4YY8H54NQIJzhMbhBg==", + "dev": true, + "requires": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.3", + "glob": "^8.1.0", + "nopt": "^6.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -7500,6 +8295,37 @@ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, + "jsdom": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", + "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", + "dev": true, + "requires": { + "abab": "^2.0.6", + "cssstyle": "^3.0.0", + "data-urls": "^4.0.0", + "decimal.js": "^10.4.3", + "domexception": "^4.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.4", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", + "xml-name-validator": "^4.0.0" + } + }, "json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -7806,6 +8632,15 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "requires": { + "abbrev": "^1.0.0" + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -7830,6 +8665,12 @@ "boolbase": "^1.0.0" } }, + "nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "dev": true + }, "object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", @@ -7910,6 +8751,15 @@ "callsites": "^3.0.0" } }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "requires": { + "entities": "^4.4.0" + } + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -8069,6 +8919,12 @@ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "dev": true }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -8212,6 +9068,12 @@ "fsevents": "~2.3.2" } }, + "rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -8253,6 +9115,15 @@ "source-map-js": ">=0.6.2 <2.0.0" } }, + "saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, "semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -8466,6 +9337,12 @@ "has-flag": "^4.0.0" } }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -8540,6 +9417,15 @@ } } }, + "tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "requires": { + "punycode": "^2.3.0" + } + }, "ts-api-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", @@ -8724,6 +9610,12 @@ "@vue/shared": "3.3.4" } }, + "vue-component-type-helpers": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-1.8.4.tgz", + "integrity": "sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==", + "dev": true + }, "vue-eslint-parser": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz", @@ -8760,6 +9652,15 @@ "semver": "^7.3.8" } }, + "w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "requires": { + "xml-name-validator": "^4.0.0" + } + }, "wait-on": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.0.1.tgz", @@ -8785,6 +9686,37 @@ } } }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true + }, + "whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "requires": { + "iconv-lite": "0.6.3" + } + }, + "whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true + }, + "whatwg-url": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", + "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "dev": true, + "requires": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -8821,12 +9753,25 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "dev": true, + "requires": {} + }, "xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "dev": true }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/web/package.json b/web/package.json index e4048b8833..3760665d12 100644 --- a/web/package.json +++ b/web/package.json @@ -27,15 +27,18 @@ "vue": "^3.3.4" }, "devDependencies": { + "@pinia/testing": "^0.1.3", "@quasar/vite-plugin": "^1.4.1", "@types/node": "^20.5.4", "@typescript-eslint/eslint-plugin": "^6.4.1", "@typescript-eslint/parser": "^6.4.1", "@vitejs/plugin-vue": "^4.2.3", + "@vue/test-utils": "^2.4.1", "cypress": "^13.0.0", "eslint": "^8.47.0", "eslint-plugin-cypress": "^2.14.0", "eslint-plugin-vue": "^9.17.0", + "jsdom": "^22.1.0", "sass": "^1.66.1", "start-server-and-test": "^2.0.0", "typescript": "^5.0.2", diff --git a/web/src/api/index.ts b/web/src/api/index.ts index 24f387aa6a..c40dff7aa8 100644 --- a/web/src/api/index.ts +++ b/web/src/api/index.ts @@ -2,9 +2,9 @@ export { api as default, useApi } from 'src/api/client'; -export type * from 'src/api/types/accounts'; -export type * from 'src/api/types/apptypes'; -export type * from 'src/api/types/connect'; -export type * from 'src/api/types/deployments'; -export type * from 'src/api/types/files'; -export type * from 'src/api/types/manifest'; +export * from 'src/api/types/accounts'; +export * from 'src/api/types/apptypes'; +export * from 'src/api/types/connect'; +export * from 'src/api/types/deployments'; +export * from 'src/api/types/files'; +export * from 'src/api/types/manifest'; diff --git a/web/src/api/types/files.ts b/web/src/api/types/files.ts index 140d5f0928..348389db48 100644 --- a/web/src/api/types/files.ts +++ b/web/src/api/types/files.ts @@ -24,7 +24,6 @@ export type DeploymentFile = { abs: string base: string rel: string - root: string size: number modifiedDatetime: string isDir: boolean diff --git a/web/src/main.ts b/web/src/main.ts index 8e9549576d..9456c3901b 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -2,7 +2,7 @@ import { createApp } from 'vue'; import { createPinia } from 'pinia'; -import { Quasar } from 'quasar'; +import { Dark, Quasar } from 'quasar'; // Import Quasar Roboto Font import '@quasar/extras/roboto-font/roboto-font.css'; @@ -20,5 +20,5 @@ const pinia = createPinia(); const app = createApp(App); app.use(pinia); -app.use(Quasar, {}); +app.use(Quasar, { plugins: { Dark } }); app.mount('#app'); diff --git a/web/tests/unit/components/configurePublish/FilesToPublish.test.ts b/web/tests/unit/components/configurePublish/FilesToPublish.test.ts new file mode 100644 index 0000000000..ed46a67297 --- /dev/null +++ b/web/tests/unit/components/configurePublish/FilesToPublish.test.ts @@ -0,0 +1,203 @@ +import { Quasar } from 'quasar'; +import { describe, expect, test, vi } from 'vitest'; +import { createTestingPinia } from '@pinia/testing'; +import { flushPromises, mount } from '@vue/test-utils'; + +import api, { AppMode, DeploymentFile, DeploymentFileType, ExclusionMatchSource, ServerType, useApi } from 'src/api'; +import FilesToPublish from 'src/components/configurePublish/FilesToPublish.vue'; +import { useDeploymentStore } from 'src/stores/deployment'; + +const fakeResponse: DeploymentFile = { + id: '.', + fileType: DeploymentFileType.DIRECTORY, + base: 'fastapi-simple', + exclusion: null, + files: [ + { + id: '.gitignore', + fileType: DeploymentFileType.REGULAR, + base: '.gitignore', + exclusion: { + source: ExclusionMatchSource.BUILT_IN, + pattern: '.gitignore', + filePath: '', + line: 0 + }, + files: [], + isDir: false, + isEntrypoint: false, + isFile: true, + modifiedDatetime: '2023-09-19T10:20:06-07:00', + rel: '.gitignore', + size: 6, + abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple/.gitignore' + }, + { + id: 'manifest.json', + fileType: DeploymentFileType.REGULAR, + base: 'manifest.json', + exclusion: { + source: ExclusionMatchSource.BUILT_IN, + pattern: 'manifest.json', + filePath: '', + line: 0 + }, + files: [], + isDir: false, + isEntrypoint: false, + isFile: true, + modifiedDatetime: '2023-08-18T11:56:15-07:00', + rel: 'manifest.json', + size: 552, + abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple/manifest.json' + }, + { + id: 'meta.yaml', + fileType: DeploymentFileType.REGULAR, + base: 'meta.yaml', + exclusion: null, + files: [], + isDir: false, + isEntrypoint: false, + isFile: true, + modifiedDatetime: '2023-08-02T15:41:24-07:00', + rel: 'meta.yaml', + size: 63, + abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple/meta.yaml' + }, + { + id: 'requirements.in', + fileType: DeploymentFileType.REGULAR, + base: 'requirements.in', + exclusion: null, + files: [], + isDir: false, + isEntrypoint: false, + isFile: true, + modifiedDatetime: '2023-08-02T15:41:24-07:00', + rel: 'requirements.in', + size: 124, + abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple/requirements.in' + }, + { + id: 'requirements.txt', + fileType: DeploymentFileType.REGULAR, + base: 'requirements.txt', + exclusion: null, + files: [], + isDir: false, + isEntrypoint: false, + isFile: true, + modifiedDatetime: '2023-08-02T15:41:24-07:00', + rel: 'requirements.txt', + size: 235, + abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple/requirements.txt' + }, + { + id: 'simple.py', + fileType: DeploymentFileType.REGULAR, + base: 'simple.py', + exclusion: null, + files: [], + isDir: false, + isEntrypoint: false, + isFile: true, + modifiedDatetime: '2023-08-02T15:41:24-07:00', + rel: 'simple.py', + size: 369, + abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple/simple.py' + } + ], + isDir: true, + isEntrypoint: false, + isFile: false, + modifiedDatetime: '2023-09-19T10:20:06-07:00', + rel: '.', + size: 256, + abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple' +}; + +vi.mock('src/api'); +vi.mocked(useApi).mockReturnValue(api); + +describe('description', () => { + test('some test description', async() => { + vi.mocked(api.files.get, { partial: true }).mockResolvedValue({ data: fakeResponse }); + + const wrapper = mount(FilesToPublish, { + global: { + plugins: [Quasar, createTestingPinia({ createSpy: vi.fn })] + } + }); + + const deploymentStore = useDeploymentStore(); + deploymentStore.deployment = { + sourcePath: 'test/sample-content/fastapi-simple', + target: { + accountName: 'dogfood', + serverType: ServerType.CONNECT, + serverUrl: '', + contentId: '', + contentName: '', + username: '', + bundleId: null, + deployedAt: null + }, + manifest: { + version: 1, + locale: '', + metadata: { + appmode: AppMode.PYTHON_FASTAPI, + entrypoint: 'simple.py', + primaryHtml: '', + }, + python: { + version: '3.11.5', + packageManager: { + name: 'pip', + packageFile: 'requirements.txt' + } + }, + packages: {}, + files: { + '.': { checksum: '' }, + 'meta.yaml': { checksum: '' }, + 'requirements.in': { checksum: '' }, + 'requirements.txt': { checksum: '' }, + 'simple.py': { checksum: '' } + } + }, + connect: { + connect: { + name: '', + connectionTimeout: null, + readTimeout: null, + initTimeout: null, + idleTimeout: null, + maxProcesses: null, + minProcesses: null, + maxConnsPerProcess: null, + loadFactor: null, + runAsCurrentUser: null, + memoryRequest: null, + memoryLimit: null, + cpuRequest: null, + cpuLimit: null + }, + environment: [ + { + name: '', + value: '', + fromEnvironment: false, + } + ] + }, + pythonRequirements: ['YW55aW89PTMuNi4yCmFzZ2lyZWY9PTMuNi4wCmNsaWNrPT04LjEuMwpmYXN0YXBpPT0wLjk1LjIKaDExPT0wLjE0LjAKaWRuYT09My40CnB5ZGFudGljPT0xLjEwLjcKcHlqd3Q9PTIuNy4wCnJzY29ubmVjdC1weXRob249PTEuMTcuMApzZW12ZXI9PTIuMTMuMApzaXg9PTEuMTYuMApzbmlmZmlvPT0xLjMuMApzdGFybGV0dGU9PTAuMjcuMAp0eXBpbmctZXh0ZW5zaW9ucz09NC41LjAKdXZpY29ybj09MC4yMi4wCg=='] + }; + await flushPromises(); + + expect(api.files.get).toHaveBeenCalledOnce(); + expect(wrapper.text()).toContain('4 files selected from test/sample-content/fastapi-simple (total = 1.0 KB)'); + }); +}); + diff --git a/web/tsconfig.json b/web/tsconfig.json index b9e9bdadb5..76198ac3ce 100644 --- a/web/tsconfig.json +++ b/web/tsconfig.json @@ -26,6 +26,12 @@ "src/*": ["src/*"] } }, - "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], + "include": [ + "src/**/*.ts", + "src/**/*.d.ts", + "src/**/*.tsx", + "src/**/*.vue", + "tests/**/*.ts" + ], "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/web/vite.config.ts b/web/vite.config.ts index 231a6ad713..ec1ac5d8e1 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -1,3 +1,5 @@ +/// + import { fileURLToPath } from 'node:url'; import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; @@ -31,5 +33,8 @@ export default defineConfig({ secure: false } } + }, + test: { + environment: 'jsdom', } });