diff --git a/cmd/world/forge/deployment.go b/cmd/world/forge/deployment.go index 09e5048..770e016 100644 --- a/cmd/world/forge/deployment.go +++ b/cmd/world/forge/deployment.go @@ -16,8 +16,8 @@ import ( var statusFailRegEx = regexp.MustCompile(`[^a-zA-Z0-9\. ]+`) -// Deploy a project -func deploy(ctx context.Context) error { +// Deployment a project +func deployment(ctx context.Context, deployType string) error { globalConfig, err := globalconfig.GetGlobalConfig() if err != nil { return eris.Wrap(err, "Failed to get global config") @@ -56,79 +56,14 @@ func deploy(ctx context.Context) error { fmt.Printf("Project Slug: %s\n", prj.Slug) fmt.Printf("Repository: %s\n\n", prj.RepoURL) - deployURL := fmt.Sprintf("%s/api/organization/%s/project/%s/deploy", baseURL, organizationID, projectID) + deployURL := fmt.Sprintf("%s/api/organization/%s/project/%s/%s", baseURL, organizationID, projectID, deployType) _, err = sendRequest(ctx, http.MethodPost, deployURL, nil) if err != nil { - return eris.Wrap(err, "Failed to deploy project") + return eris.Wrap(err, fmt.Sprintf("Failed to %s project", deployType)) } - fmt.Println("\n✨ Your deployment is being processed! ✨") - fmt.Println("\nTo check the status of your deployment, run:") - fmt.Println(" $ 'world forge deployment status'") - - return nil -} - -// Destroy a project -func destroy(ctx context.Context) error { - globalConfig, err := globalconfig.GetGlobalConfig() - if err != nil { - return eris.Wrap(err, "Failed to get global config") - } - - projectID := globalConfig.ProjectID - organizationID := globalConfig.OrganizationID - - if organizationID == "" { - printNoSelectedOrganization() - return nil - } - - if projectID == "" { - printNoSelectedProject() - return nil - } - - // Get organization details - org, err := getSelectedOrganization(ctx) - if err != nil { - return eris.Wrap(err, "Failed to get organization details") - } - - // Get project details - prj, err := getSelectedProject(ctx) - if err != nil { - return eris.Wrap(err, "Failed to get project details") - } - - fmt.Println("Project Details") - fmt.Println("-----------------") - fmt.Printf("Organization: %s\n", org.Name) - fmt.Printf("Org Slug: %s\n", org.Slug) - fmt.Printf("Project: %s\n", prj.Name) - fmt.Printf("Project Slug: %s\n", prj.Slug) - fmt.Printf("Repository: %s\n\n", prj.RepoURL) - - fmt.Print("Are you sure you want to destroy this project? (y/N): ") - response, err := getInput() - if err != nil { - return eris.Wrap(err, "Failed to read response") - } - - response = strings.ToLower(strings.TrimSpace(response)) - if response != "y" { - fmt.Println("Destroy cancelled") - return nil - } - - destroyURL := fmt.Sprintf("%s/api/organization/%s/project/%s/destroy", baseURL, organizationID, projectID) - _, err = sendRequest(ctx, http.MethodPost, destroyURL, nil) - if err != nil { - return eris.Wrap(err, "Failed to destroy project") - } - - fmt.Println("\n🗑️ Your destroy request is being processed!") - fmt.Println("\nTo check the status of your destroy request, run:") + fmt.Printf("\n✨ Your %s is being processed! ✨\n", deployType) + fmt.Printf("\nTo check the status of your %s, run:\n", deployType) fmt.Println(" $ 'world forge deployment status'") return nil diff --git a/cmd/world/forge/forge.go b/cmd/world/forge/forge.go index eec6861..067c96a 100644 --- a/cmd/world/forge/forge.go +++ b/cmd/world/forge/forge.go @@ -159,7 +159,7 @@ var ( if !checkLogin() { return nil } - return deploy(cmd.Context()) + return deployment(cmd.Context(), "deploy") }, } @@ -170,7 +170,18 @@ var ( if !checkLogin() { return nil } - return destroy(cmd.Context()) + return deployment(cmd.Context(), "destroy") + }, + } + + resetCmd = &cobra.Command{ + Use: "reset", + Short: "Reset a project", + RunE: func(cmd *cobra.Command, _ []string) error { + if !checkLogin() { + return nil + } + return deployment(cmd.Context(), "reset") }, } @@ -218,5 +229,6 @@ func init() { deploymentCmd.AddCommand(deployCmd) deploymentCmd.AddCommand(destroyCmd) deploymentCmd.AddCommand(statusCmd) + deploymentCmd.AddCommand(resetCmd) BaseCmd.AddCommand(deploymentCmd) } diff --git a/cmd/world/forge/forge_test.go b/cmd/world/forge/forge_test.go index b6a3c37..d4254cd 100644 --- a/cmd/world/forge/forge_test.go +++ b/cmd/world/forge/forge_test.go @@ -61,6 +61,8 @@ func (s *ForgeTestSuite) SetupTest() { s.handleDeploy(w, r) case "/api/organization/test-org-id/project/test-project-id/destroy": s.handleDestroy(w, r) + case "/api/organization/test-org-id/project/test-project-id/reset": + s.handleReset(w, r) case "/api/organization/invalid-org-id/project/test-project-id/deploy": http.Error(w, "Organization not found", http.StatusNotFound) case "/api/organization/test-org-id/project/invalid-project-id/deploy": @@ -375,6 +377,14 @@ func (s *ForgeTestSuite) handleGetToken(w http.ResponseWriter, r *http.Request) } } +func (s *ForgeTestSuite) handleReset(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + s.writeJSON(w, map[string]interface{}{"data": "reset started"}) +} + func (s *ForgeTestSuite) writeJSON(w http.ResponseWriter, data interface{}) { w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(data) @@ -652,7 +662,7 @@ func (s *ForgeTestSuite) TestDeploy() { err := globalconfig.SaveGlobalConfig(tc.config) s.Require().NoError(err) - err = deploy(s.ctx) + err = deployment(s.ctx, "deploy") if tc.expectedError { s.Require().Error(err) } else { @@ -843,7 +853,95 @@ func (s *ForgeTestSuite) TestDestroy() { } defer func() { getInput = originalGetInput }() - err = destroy(s.ctx) + err = deployment(s.ctx, "destroy") + if tc.expectedError { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} + +func (s *ForgeTestSuite) TestReset() { + testCases := []struct { + name string + config globalconfig.GlobalConfig + input string + expectedError bool + }{ + { + name: "Success", + config: globalconfig.GlobalConfig{ + OrganizationID: "test-org-id", + ProjectID: "test-project-id", + Credential: globalconfig.Credential{ + Token: "test-token", + }, + }, + input: "y", + expectedError: false, + }, + { + name: "Error - Invalid organization ID", + config: globalconfig.GlobalConfig{ + OrganizationID: "invalid-org-id", + ProjectID: "test-project-id", + Credential: globalconfig.Credential{ + Token: "test-token", + }, + }, + input: "y", + expectedError: true, + }, + { + name: "Error - Invalid project ID", + config: globalconfig.GlobalConfig{ + OrganizationID: "test-org-id", + ProjectID: "invalid-project-id", + Credential: globalconfig.Credential{ + Token: "test-token", + }, + }, + input: "y", + expectedError: true, + }, + { + name: "Error - No organization selected", + config: globalconfig.GlobalConfig{ + ProjectID: "test-project-id", + Credential: globalconfig.Credential{ + Token: "test-token", + }, + }, + input: "y", + expectedError: false, + }, + { + name: "Error - No project selected", + config: globalconfig.GlobalConfig{ + OrganizationID: "test-org-id", + Credential: globalconfig.Credential{ + Token: "test-token", + }, + }, + input: "y", + expectedError: false, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + // Setup test config + err := globalconfig.SaveGlobalConfig(tc.config) + s.Require().NoError(err) + + getInput = func() (string, error) { + return tc.input, nil + } + defer func() { getInput = originalGetInput }() + + err = deployment(s.ctx, "reset") if tc.expectedError { s.Require().Error(err) } else {