diff --git a/core/core.go b/core/core.go index 22d7f5c..e69e148 100644 --- a/core/core.go +++ b/core/core.go @@ -27,6 +27,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "io" "net/http" "path/filepath" @@ -48,43 +49,15 @@ const ( ErrNoCoreURL = "no coreURL specified in config" ErrSomeResendsFailed = "some queued environments failed to be resent from core to builder" - graphQLEndpoint = "/graphql" - resendEndpoint = "/resend-pending-builds" + resendEndpoint = "/resend-pending-builds" + createEndpoint = "/create-environment" + deleteEndpoint = "/delete-environment" ) -type gqlVariables struct { - Name string `json:"name"` - Path string `json:"path"` - Description string `json:"description,omitempty"` - Packages Packages `json:"packages,omitempty"` -} - -func newGQLVariables(fullPath, desc string, pkgs Packages) gqlVariables { - return gqlVariables{ - Name: filepath.Base(fullPath), - Path: filepath.Dir(fullPath), - Description: desc, - Packages: pkgs, - } -} - -type gqlQuery struct { - Variables gqlVariables `json:"variables"` - Query string `json:"query"` -} - // EnvironmentResponse is the kind of return value we get from the core. type EnvironmentResponse struct { - TypeName string `json:"__typename"` - Message string `json:"message"` -} - -// Response represents a response to a GraphQL operation. -type Response struct { - Data struct { - CreateEnvironment *EnvironmentResponse `json:"createEnvironment"` - DeleteEnvironment *EnvironmentResponse `json:"deleteEnvironment"` - } `json:"data"` + Message string `json:"message"` + Error string `json:"error"` } // Core is used to interact with a real softpack-core service. @@ -111,15 +84,6 @@ func toJSON(thing any) io.Reader { return &buf } -func (c *Core) doGQLCoreRequest(graphQLPacket io.Reader) error { - resp, err := c.doCoreRequest(graphQLEndpoint, graphQLPacket) - if err != nil { - return err - } - - return handleGQLCoreResponse(resp) -} - func (c *Core) doCoreRequest(endpoint string, content io.Reader) (*http.Response, error) { req, err := http.NewRequestWithContext( context.Background(), @@ -136,29 +100,6 @@ func (c *Core) doCoreRequest(endpoint string, content io.Reader) (*http.Response return http.DefaultClient.Do(req) } -func handleGQLCoreResponse(resp *http.Response) error { - var cr Response - - err := json.NewDecoder(resp.Body).Decode(&cr) - if err != nil { - return err - } - - if cr.Data.DeleteEnvironment != nil { - if cr.Data.DeleteEnvironment.TypeName != DeleteMutationSuccess { - return internal.Error(cr.Data.DeleteEnvironment.Message) - } - } - - if cr.Data.CreateEnvironment != nil { - if cr.Data.CreateEnvironment.TypeName != createMutationSuccess { - return internal.Error(cr.Data.CreateEnvironment.Message) - } - } - - return nil -} - // ResendResponse is the response that the core service sends when a resend // request is sent to it. type ResendResponse struct { @@ -194,3 +135,53 @@ func (c *Core) ResendPendingBuilds() error { return nil } + +type environmentInput struct { + Name string `json:"name"` + Path string `json:"path"` + Description string `json:"description"` + Packages Packages `json:"packages"` +} + +// Create contacts the core to schedule an environment build. +func (c *Core) Create(path, desc string, pkgs Packages) error { + return handleResponse(c.doCoreRequest(createEndpoint, toJSON(environmentInput{ + Name: filepath.Base(path), + Path: filepath.Dir(path), + Description: desc, + Packages: pkgs, + }))) +} + +func handleResponse(resp *http.Response, err error) error { + if err != nil { + return err + } + + defer resp.Body.Close() + + var r EnvironmentResponse + + if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { + return err + } + + if r.Error != "" { + return errors.New(r.Error) //nolint:goerr113 + } + + return nil +} + +type deleteEnvironmentInput struct { + Name string `json:"name"` + Path string `json:"path"` +} + +// Delete contacts the core to delete an environment. +func (c *Core) Delete(path string) error { + return handleResponse(c.doCoreRequest(deleteEndpoint, toJSON(deleteEnvironmentInput{ + Name: filepath.Base(path), + Path: filepath.Dir(path), + }))) +} diff --git a/core/core_test.go b/core/core_test.go index 65d41a1..d35f6b6 100644 --- a/core/core_test.go +++ b/core/core_test.go @@ -49,19 +49,6 @@ func TestCore(t *testing.T) { }, } - Convey("You can create a gqlQuery", func() { - gq := newCreateMutation(path, desc, pkgs) - So(gq, ShouldResemble, &gqlQuery{ - Variables: gqlVariables{ - Name: "env", - Path: "users/foo", - Description: desc, - Packages: pkgs, - }, - Query: createMutationQuery, - }) - }) - conf, err := config.GetConfig("") if err != nil || conf.CoreURL == "" || conf.ListenURL == "" { _, err = New(conf) diff --git a/core/create.go b/core/create.go deleted file mode 100644 index 87af48b..0000000 --- a/core/create.go +++ /dev/null @@ -1,58 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2024 Genome Research Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ******************************************************************************/ - -package core - -const createMutationSuccess = "CreateEnvironmentSuccess" - -const createMutationQuery = ` -mutation ($name: String!, $description: String!, $path: String!, $packages: [PackageInput!]!) { - createEnvironment( - env: {name: $name, description: $description, path: $path, packages: $packages} - ) { - __typename - ... on ` + createMutationSuccess + ` { - message - __typename - } - ... on Error { - message - __typename - } - } -} -` - -func newCreateMutation(path, description string, packages Packages) *gqlQuery { - return &gqlQuery{ - Variables: newGQLVariables(path, description, packages), - Query: createMutationQuery, - } -} - -// Create contacts the core to schedule an environment build. -func (c *Core) Create(path, desc string, pkgs Packages) error { - gq := newCreateMutation(path, desc, pkgs) - - return c.doGQLCoreRequest(toJSON(gq)) -} diff --git a/core/delete.go b/core/delete.go deleted file mode 100644 index caa2387..0000000 --- a/core/delete.go +++ /dev/null @@ -1,59 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2024 Genome Research Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ******************************************************************************/ - -package core - -const DeleteMutationSuccess = "DeleteEnvironmentSuccess" - -const deleteMutationQuery = ` -mutation ($name: String!, $path: String!) { - deleteEnvironment( - name: $name - path: $path - ) { - __typename - ... on ` + DeleteMutationSuccess + ` { - message - } - ... on EnvironmentNotFoundError { - message - path - name - } - } -} -` - -func newDeleteMutation(path string) *gqlQuery { - return &gqlQuery{ - Variables: newGQLVariables(path, "", nil), - Query: deleteMutationQuery, - } -} - -// Delete contacts the core to delete an environment. -func (c *Core) Delete(path string) error { - gq := newDeleteMutation(path) - - return c.doGQLCoreRequest(toJSON(gq)) -} diff --git a/remove/remove_test.go b/remove/remove_test.go index d850698..295060b 100644 --- a/remove/remove_test.go +++ b/remove/remove_test.go @@ -38,7 +38,7 @@ func TestRemove(t *testing.T) { envPath := filepath.Join(groupsDir, group, env) - var response core.Response + var response core.EnvironmentResponse mockCore := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { json.NewEncoder(w).Encode(response) //nolint:errcheck @@ -88,9 +88,8 @@ func TestRemove(t *testing.T) { }) Convey("Remove() call fails if environment is not successfully removed from Core", func() { - response.Data.DeleteEnvironment = &core.EnvironmentResponse{ - TypeName: "EnvironmentNotFoundError", - Message: "No environment with this name found in this location.", + response = core.EnvironmentResponse{ + Error: "No environment with this name found in this location.", } err := Remove(conf, s3Mock, envPath, version) @@ -104,9 +103,8 @@ func TestRemove(t *testing.T) { }) Convey("Can use Remove() to delete an existing environment", func() { - response.Data.DeleteEnvironment = &core.EnvironmentResponse{ - TypeName: core.DeleteMutationSuccess, - Message: "Successfully deleted the environment", + response = core.EnvironmentResponse{ + Message: "Successfully deleted the environment", } modulePath := filepath.Join(conf.Module.ModuleInstallDir, groupsDir, group, env) @@ -124,9 +122,8 @@ func TestRemove(t *testing.T) { }) Convey("Remove() only deletes the environment matching the version specified", func() { - response.Data.DeleteEnvironment = &core.EnvironmentResponse{ - TypeName: core.DeleteMutationSuccess, - Message: "Successfully deleted the environment", + response = core.EnvironmentResponse{ + Message: "Successfully deleted the environment", } newVersion := genRandString(4)