From f939895c73813477f36a9ab8e094b86fd69478f2 Mon Sep 17 00:00:00 2001 From: Jens Feodor Nielsen Date: Thu, 13 Jun 2024 14:06:15 +0200 Subject: [PATCH] use manifest deploy section in deploy command --- cli/cmd/deploy/deploy.go | 31 ++++++++--- cli/cmd/deploy/deploy_test.go | 52 +++++++++++++++++- cli/testdata/streamlit_app/numerous.toml | 6 +- .../streamlit_app_without_deploy/app.py | 10 ++++ .../app_cover.jpg | Bin 0 -> 2233 bytes .../numerous.toml | 9 +++ .../requirements.txt | 1 + 7 files changed, 97 insertions(+), 12 deletions(-) create mode 100644 cli/testdata/streamlit_app_without_deploy/app.py create mode 100644 cli/testdata/streamlit_app_without_deploy/app_cover.jpg create mode 100644 cli/testdata/streamlit_app_without_deploy/numerous.toml create mode 100644 cli/testdata/streamlit_app_without_deploy/requirements.txt diff --git a/cli/cmd/deploy/deploy.go b/cli/cmd/deploy/deploy.go index 61ca547..c1816e1 100644 --- a/cli/cmd/deploy/deploy.go +++ b/cli/cmd/deploy/deploy.go @@ -35,26 +35,39 @@ var ( ) func Deploy(ctx context.Context, apps AppService, appDir, projectDir, slug string, appName string, verbose bool) error { + task := output.StartTask("Loading app configuration") + manifest, err := manifest.LoadManifest(filepath.Join(appDir, manifest.ManifestPath)) + if err != nil { + task.Error() + output.PrintErrorAppNotInitialized(appDir) + + return err + } + + secrets := loadSecretsFromEnv(appDir) + + if slug == "" && manifest.Deployment != nil { + slug = manifest.Deployment.OrganizationSlug + } + if !validate.IsValidIdentifier(slug) { + task.Error() output.PrintError("Error: Invalid organization %q.", "Must contain only lower-case alphanumerical characters and dashes.", slug) + return ErrInvalidSlug } - if !validate.IsValidIdentifier(appName) { - output.PrintError("Error: Invalid app name %q.", "Must contain only lower-case alphanumerical characters and dashes.", appName) - return ErrInvalidAppName + if appName == "" && manifest.Deployment != nil { + appName = manifest.Deployment.AppName } - task := output.StartTask("Loading app configuration") - manifest, err := manifest.LoadManifest(filepath.Join(appDir, manifest.ManifestPath)) - if err != nil { + if !validate.IsValidIdentifier(appName) { task.Error() - output.PrintErrorAppNotInitialized(appDir) + output.PrintError("Error: Invalid app name %q.", "Must contain only lower-case alphanumerical characters and dashes.", appName) - return err + return ErrInvalidAppName } - secrets := loadSecretsFromEnv(appDir) task.Done() task = output.StartTask("Registering new version") diff --git a/cli/cmd/deploy/deploy_test.go b/cli/cmd/deploy/deploy_test.go index 57be4ed..84954c8 100644 --- a/cli/cmd/deploy/deploy_test.go +++ b/cli/cmd/deploy/deploy_test.go @@ -68,16 +68,64 @@ func TestDeploy(t *testing.T) { }) t.Run("given invalid slug then it returns error", func(t *testing.T) { - err := Deploy(context.TODO(), nil, ".", "", "Some Invalid Organization Slug", appName, false) + appDir := t.TempDir() + copyTo(t, "../../testdata/streamlit_app", appDir) + + err := Deploy(context.TODO(), nil, appDir, "", "Some Invalid Organization Slug", appName, false) assert.ErrorIs(t, err, ErrInvalidSlug) }) t.Run("given invalid app name then it returns error", func(t *testing.T) { - err := Deploy(context.TODO(), nil, ".", "", slug, "Some Invalid App Name", false) + appDir := t.TempDir() + copyTo(t, "../../testdata/streamlit_app", appDir) + + err := Deploy(context.TODO(), nil, appDir, "", slug, "Some Invalid App Name", false) assert.ErrorIs(t, err, ErrInvalidAppName) }) + + t.Run("given no slug or app name arguments and manifest with deployment and then it uses manifest deployment", func(t *testing.T) { + appDir := t.TempDir() + copyTo(t, "../../testdata/streamlit_app", appDir) + + apps := &mockAppService{} + apps.On("ReadApp", mock.Anything, mock.Anything).Return(app.ReadAppOutput{}, app.ErrAppNotFound) + apps.On("Create", mock.Anything, mock.Anything).Return(app.CreateAppOutput{AppID: appID}, nil) + apps.On("CreateVersion", mock.Anything, mock.Anything).Return(app.CreateAppVersionOutput{AppVersionID: appVersionID}, nil) + apps.On("AppVersionUploadURL", mock.Anything, mock.Anything).Return(app.AppVersionUploadURLOutput{UploadURL: uploadURL}, nil) + apps.On("UploadAppSource", mock.Anything, mock.Anything).Return(nil) + apps.On("DeployApp", mock.Anything, mock.Anything).Return(app.DeployAppOutput{DeploymentVersionID: deployVersionID}, nil) + apps.On("DeployEvents", mock.Anything, mock.Anything).Return(nil) + + err := Deploy(context.TODO(), apps, appDir, "", "", "", false) + + if assert.NoError(t, err) { + expectedInput := app.CreateAppInput{OrganizationSlug: "organization-slug-in-manifest", Name: "app-name-in-manifest", DisplayName: "Streamlit App With Deploy"} + apps.AssertCalled(t, "Create", mock.Anything, expectedInput) + } + }) + + t.Run("given slug or app name arguments and manifest with deployment and then arguments override manifest deployment", func(t *testing.T) { + appDir := t.TempDir() + copyTo(t, "../../testdata/streamlit_app", appDir) + + apps := &mockAppService{} + apps.On("ReadApp", mock.Anything, mock.Anything).Return(app.ReadAppOutput{}, app.ErrAppNotFound) + apps.On("Create", mock.Anything, mock.Anything).Return(app.CreateAppOutput{AppID: appID}, nil) + apps.On("CreateVersion", mock.Anything, mock.Anything).Return(app.CreateAppVersionOutput{AppVersionID: appVersionID}, nil) + apps.On("AppVersionUploadURL", mock.Anything, mock.Anything).Return(app.AppVersionUploadURLOutput{UploadURL: uploadURL}, nil) + apps.On("UploadAppSource", mock.Anything, mock.Anything).Return(nil) + apps.On("DeployApp", mock.Anything, mock.Anything).Return(app.DeployAppOutput{DeploymentVersionID: deployVersionID}, nil) + apps.On("DeployEvents", mock.Anything, mock.Anything).Return(nil) + + err := Deploy(context.TODO(), apps, appDir, "", "organization-slug-in-argument", "app-name-in-argument", false) + + if assert.NoError(t, err) { + expectedInput := app.CreateAppInput{OrganizationSlug: "organization-slug-in-argument", Name: "app-name-in-argument", DisplayName: "Streamlit App With Deploy"} + apps.AssertCalled(t, "Create", mock.Anything, expectedInput) + } + }) } func copyTo(t *testing.T, src string, dest string) { diff --git a/cli/testdata/streamlit_app/numerous.toml b/cli/testdata/streamlit_app/numerous.toml index 22801dc..250923d 100644 --- a/cli/testdata/streamlit_app/numerous.toml +++ b/cli/testdata/streamlit_app/numerous.toml @@ -1,4 +1,4 @@ -name = "streamlit_example" +name = "Streamlit App With Deploy" description = "" library = "streamlit" python = "3.11" @@ -7,3 +7,7 @@ requirements_file = "requirements.txt" port = 80 cover_image = "app_cover.jpg" exclude = ["*venv", "venv*", ".git"] + +[deploy] +organization = "organization-slug-in-manifest" +name = "app-name-in-manifest" diff --git a/cli/testdata/streamlit_app_without_deploy/app.py b/cli/testdata/streamlit_app_without_deploy/app.py new file mode 100644 index 0000000..822adda --- /dev/null +++ b/cli/testdata/streamlit_app_without_deploy/app.py @@ -0,0 +1,10 @@ +import streamlit as st + +st.title("Counter Example") +count = 0 + +increment = st.button("Increment") +if increment: + count += 1 + +st.write("Count = ", count) diff --git a/cli/testdata/streamlit_app_without_deploy/app_cover.jpg b/cli/testdata/streamlit_app_without_deploy/app_cover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d86fbc92b9ad4aac920423c0767ae12ac763ac18 GIT binary patch literal 2233 zcmd^B`&ZK07RPIbXqFFr#Pu;E2G_yLF*H+25dv?cVs=Fdxno}w!W{M^$&ewjv|G})a&pLbWb3S{Yb=GHn)@G9f ziADx60}u#g?W;;ssUZM@^Qq!9G z>e$%rngpA@*8iyG9j*TFw2ykA^n7N0M@RnkhtXhc>G@yxB@5dv)!94N}C4 zF^3!0X;8VwxknGZOh@9}abb#{Gi22$7J`mv>O#IPTUYq9w zJwukpDuaD942F|)*2C6C7#kHF>Tr4_yU^`hp?T!hxNT1BsEm~TxK*mrU^vTCc{c%d zqWZ?r!Wiew(B{U%S!b|o_3?2lV7rzfkzo78^S&t|CkLdCf~R@2=Yu&_Cr@fn9}%OdAhx z{HDI2dCt4Fh87Kb=Eck^@Pe{0691y6*M}wJ#G@Ab**}G$-FZ~#e$ zhU-gQ5167kWUmk)fJj^srszVlmn+=Y4)}Kyhz1TFWRixEJo;{YRx3o(!`|g*%rP;8 zumD0hn(pyOogg8s3dyU#_ZPXF%>uI355L=ab6{`~IY1Rz4;Cd2ETYW#wJaMN}qZbhEb_)82NXp%rc_7V^gDEXq%+~f~Hcb z_(ThM>e&dPNF;jq@#Dv(ZY3-wCB=PpwsdA@=D3ll3c04$YHRbQDQ&g2wF`PpfT$`o zEu_tga;wI!5Msb|b9#DuVQy|NORFyd#lIT1ae8iLewNSHZoM87X2PW(nrNw4divfg zGeZ&g5Ugmt%fDeb>0DX4d0(9cJHa4k`SMZR@~-3oL4w{CY9`v8c}%Hz0P~$Z_f?D) lAX<^OdT<`-Pitk{x{qGA&p+)v@;xwVfcy!8_&Quv)*pNN#Ss7i literal 0 HcmV?d00001 diff --git a/cli/testdata/streamlit_app_without_deploy/numerous.toml b/cli/testdata/streamlit_app_without_deploy/numerous.toml new file mode 100644 index 0000000..a17de6b --- /dev/null +++ b/cli/testdata/streamlit_app_without_deploy/numerous.toml @@ -0,0 +1,9 @@ +name = "Streamlit App Without Deploy" +description = "" +library = "streamlit" +python = "3.11" +app_file = "app.py" +requirements_file = "requirements.txt" +port = 80 +cover_image = "app_cover.jpg" +exclude = ["*venv", "venv*", ".git"] diff --git a/cli/testdata/streamlit_app_without_deploy/requirements.txt b/cli/testdata/streamlit_app_without_deploy/requirements.txt new file mode 100644 index 0000000..12a4706 --- /dev/null +++ b/cli/testdata/streamlit_app_without_deploy/requirements.txt @@ -0,0 +1 @@ +streamlit