diff --git a/nitric/lifecycle/lifecycle.go b/nitric/lifecycle/lifecycle.go new file mode 100644 index 0000000..e291d69 --- /dev/null +++ b/nitric/lifecycle/lifecycle.go @@ -0,0 +1,97 @@ +// Copyright 2024, Nitric Technologies Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package lifecycle + +import ( + "fmt" + "os" +) + +// LifecycleStage represents the different stages of Nitric execution +type LifecycleStage string + +const ( + // LocalRun represents local development run (using nitric run/start) + LocalRun LifecycleStage = "run" + // Build represents local development requirements building/collection (using nitric up) + Build LifecycleStage = "build" + // Cloud represents when the code is running in a deployed environment + Cloud LifecycleStage = "cloud" +) + +const ( + // NITRIC_ENVIRONMENT is the environment variable key used to determine the current Nitric lifecycle + NITRIC_ENVIRONMENT = "NITRIC_ENVIRONMENT" +) + +// GetCurrentLifecycle returns the current lifecycle stage +func GetCurrentLifecycle() (LifecycleStage, error) { + lifecycle := os.Getenv(NITRIC_ENVIRONMENT) + if lifecycle == "" { + return "", fmt.Errorf("unable to determine the current Nitric lifecycle, please ensure the %s environment variable is set", NITRIC_ENVIRONMENT) + } + + stage := LifecycleStage(lifecycle) + switch stage { + case LocalRun, Build, Cloud: + return stage, nil + default: + return "", fmt.Errorf("invalid lifecycle stage: %s", lifecycle) + } +} + +// IsInLifecycle checks if the current environment is one of the provided stages +func IsInLifecycle(stages ...LifecycleStage) bool { + currentStage, err := GetCurrentLifecycle() + if err != nil { + return false + } + + for _, stage := range stages { + if currentStage == stage { + return true + } + } + return false +} + +// WhenInLifecycles executes the provided callback if the current environment is one of the provided stages +func WhenInLifecycles[T any](stages []LifecycleStage, callback func() T) T { + if IsInLifecycle(stages...) { + return callback() + } + var zero T + return zero +} + +// WhenRunning executes the provided callback if the current environment is running (LocalRun or Cloud) +func WhenRunning[T any](callback func() T) T { + return WhenInLifecycles([]LifecycleStage{LocalRun, Cloud}, callback) +} + +// WhenCollecting executes the provided callback if the current environment is collecting requirements (Build) +func WhenCollecting[T any](callback func() T) T { + return WhenInLifecycles([]LifecycleStage{Build}, callback) +} + +// IsRunning checks if the current lifecycle is running the app (LocalRun or Cloud) +func IsRunning() bool { + return IsInLifecycle(LocalRun, Cloud) +} + +// IsCollecting checks if the current lifecycle is collecting application requirements (Build) +func IsCollecting() bool { + return IsInLifecycle(Build) +} diff --git a/nitric/lifecycle/lifecycle_suite_test.go b/nitric/lifecycle/lifecycle_suite_test.go new file mode 100644 index 0000000..43fd590 --- /dev/null +++ b/nitric/lifecycle/lifecycle_suite_test.go @@ -0,0 +1,27 @@ +// Copyright 2024, Nitric Technologies Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package lifecycle_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestLifecycle(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Lifecycle Suite") +} diff --git a/nitric/lifecycle/lifecycle_test.go b/nitric/lifecycle/lifecycle_test.go new file mode 100644 index 0000000..070ac6c --- /dev/null +++ b/nitric/lifecycle/lifecycle_test.go @@ -0,0 +1,165 @@ +// Copyright 2024, Nitric Technologies Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package lifecycle_test + +import ( + "os" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/nitrictech/go-sdk/nitric/lifecycle" +) + +var _ = Describe("Lifecycle", func() { + BeforeEach(func() { + // Clear environment before each test + os.Unsetenv(lifecycle.NITRIC_ENVIRONMENT) + }) + + Describe("GetCurrentLifecycle", func() { + Context("when environment variable is set to valid stages", func() { + It("should return LocalRun stage", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "run") + stage, err := lifecycle.GetCurrentLifecycle() + Expect(err).NotTo(HaveOccurred()) + Expect(stage).To(Equal(lifecycle.LocalRun)) + }) + + It("should return Build stage", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "build") + stage, err := lifecycle.GetCurrentLifecycle() + Expect(err).NotTo(HaveOccurred()) + Expect(stage).To(Equal(lifecycle.Build)) + }) + + It("should return Cloud stage", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "cloud") + stage, err := lifecycle.GetCurrentLifecycle() + Expect(err).NotTo(HaveOccurred()) + Expect(stage).To(Equal(lifecycle.Cloud)) + }) + }) + + Context("when environment variable is not set", func() { + It("should return an error", func() { + stage, err := lifecycle.GetCurrentLifecycle() + Expect(err).To(HaveOccurred()) + Expect(stage).To(BeEmpty()) + }) + }) + + Context("when environment variable is set to invalid stage", func() { + It("should return an error", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "invalid") + stage, err := lifecycle.GetCurrentLifecycle() + Expect(err).To(HaveOccurred()) + Expect(stage).To(BeEmpty()) + }) + }) + }) + + Describe("IsInLifecycle", func() { + Context("when current stage matches one of the provided stages", func() { + It("should return true for LocalRun", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "run") + result := lifecycle.IsInLifecycle(lifecycle.LocalRun, lifecycle.Cloud) + Expect(result).To(BeTrue()) + }) + + It("should return true for Cloud", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "cloud") + result := lifecycle.IsInLifecycle(lifecycle.LocalRun, lifecycle.Cloud) + Expect(result).To(BeTrue()) + }) + }) + + Context("when current stage does not match any of the provided stages", func() { + It("should return false", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "build") + result := lifecycle.IsInLifecycle(lifecycle.LocalRun, lifecycle.Cloud) + Expect(result).To(BeFalse()) + }) + }) + }) + + Describe("WhenInLifecycles", func() { + Context("when current stage matches one of the provided stages", func() { + It("should execute the callback", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "run") + result := lifecycle.WhenInLifecycles([]lifecycle.LifecycleStage{lifecycle.LocalRun, lifecycle.Cloud}, func() string { + return "executed" + }) + Expect(result).To(Equal("executed")) + }) + }) + + Context("when current stage does not match any of the provided stages", func() { + It("should not execute the callback and return zero value", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "build") + result := lifecycle.WhenInLifecycles([]lifecycle.LifecycleStage{lifecycle.LocalRun, lifecycle.Cloud}, func() string { + return "executed" + }) + Expect(result).To(BeEmpty()) + }) + }) + }) + + Describe("IsRunning", func() { + Context("when in LocalRun stage", func() { + It("should return true", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "run") + Expect(lifecycle.IsRunning()).To(BeTrue()) + }) + }) + + Context("when in Cloud stage", func() { + It("should return true", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "cloud") + Expect(lifecycle.IsRunning()).To(BeTrue()) + }) + }) + + Context("when in Build stage", func() { + It("should return false", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "build") + Expect(lifecycle.IsRunning()).To(BeFalse()) + }) + }) + }) + + Describe("IsCollecting", func() { + Context("when in Build stage", func() { + It("should return true", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "build") + Expect(lifecycle.IsCollecting()).To(BeTrue()) + }) + }) + + Context("when in LocalRun stage", func() { + It("should return false", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "run") + Expect(lifecycle.IsCollecting()).To(BeFalse()) + }) + }) + + Context("when in Cloud stage", func() { + It("should return false", func() { + os.Setenv(lifecycle.NITRIC_ENVIRONMENT, "cloud") + Expect(lifecycle.IsCollecting()).To(BeFalse()) + }) + }) + }) +})