Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions cmd/airflow_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import (
"path/filepath"

"github.com/astronomer/astro-cli/airflow/runtimes"
"github.com/astronomer/astro-cli/cmd/utils"
"github.com/astronomer/astro-cli/config"
"github.com/astronomer/astro-cli/pkg/ansi"
"github.com/astronomer/astro-cli/pkg/input"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)

Expand All @@ -28,7 +30,7 @@ func ConfigureContainerRuntime(_ *cobra.Command, _ []string) error {
// EnsureRuntime is a pre-run hook that ensures that the project directory exists
// and starts the container runtime if necessary.
func EnsureRuntime(cmd *cobra.Command, args []string) error {
if err := utils.EnsureProjectDir(cmd, args); err != nil {
if err := EnsureProjectDirOrInit(cmd, args); err != nil {
return err
}

Expand All @@ -50,7 +52,7 @@ func EnsureRuntime(cmd *cobra.Command, args []string) error {
// SetRuntimeIfExists is a pre-run hook that ensures the project directory exists
// and sets the container runtime if its running, otherwise we bail with an error message.
func SetRuntimeIfExists(cmd *cobra.Command, args []string) error {
if err := utils.EnsureProjectDir(cmd, args); err != nil {
if err := EnsureProjectDirOrInit(cmd, args); err != nil {
return err
}
return containerRuntime.Configure()
Expand All @@ -59,7 +61,7 @@ func SetRuntimeIfExists(cmd *cobra.Command, args []string) error {
// KillPreRunHook sets the container runtime if its running,
// otherwise we bail with an error message.
func KillPreRunHook(cmd *cobra.Command, args []string) error {
if err := utils.EnsureProjectDir(cmd, args); err != nil {
if err := EnsureProjectDirOrInit(cmd, args); err != nil {
return err
}
return containerRuntime.ConfigureOrKill()
Expand All @@ -71,3 +73,26 @@ func KillPostRunHook(_ *cobra.Command, _ []string) error {
// Kill the runtime.
return containerRuntime.Kill()
}

// EnsureProjectDirOrInit checks if the current directory is an Astro project.
// If it is not, it prompts the user to initialize one. If the user confirms,
// it runs astro dev init in the current directory.
func EnsureProjectDirOrInit(cmd *cobra.Command, args []string) error {
isProjectDir, err := config.IsProjectDir(config.WorkingPath)
if err != nil {
return errors.Wrap(err, ansi.Red("failed to verify that your working directory is an Astro project.\nTry running astro dev init to turn your working directory into an Astro project"))
}

if !isProjectDir {
confirmed, err := input.Confirm("This is not an Astro project directory. Would you like to initialize one here?")
if err != nil {
return errors.New(ansi.Red("this is not an Astro project directory.\nChange to another directory or run astro dev init to turn your working directory into an Astro project\n"))
}
if !confirmed {
return errors.New(ansi.Red("this is not an Astro project directory.\nChange to another directory or run astro dev init to turn your working directory into an Astro project\n"))
}
return airflowInit(newAirflowInitCmd(), []string{})
}

return nil
}
103 changes: 103 additions & 0 deletions cmd/airflow_hooks_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package cmd

import (
"os"
"testing"

"github.com/astronomer/astro-cli/config"
testUtil "github.com/astronomer/astro-cli/pkg/testing"

"github.com/spf13/cobra"
"github.com/stretchr/testify/suite"
)

type AirflowHooksSuite struct {
suite.Suite
tempDir string
}

func TestAirflowHooks(t *testing.T) {
suite.Run(t, new(AirflowHooksSuite))
}

func (s *AirflowHooksSuite) SetupTest() {
testUtil.InitTestConfig(testUtil.LocalPlatform)
dir, err := os.MkdirTemp("", "test_hooks_temp_dir_*")
if err != nil {
s.T().Fatalf("failed to create temp dir: %v", err)
}
s.tempDir = dir
config.WorkingPath = s.tempDir
}

func (s *AirflowHooksSuite) SetupSubTest() {
testUtil.InitTestConfig(testUtil.LocalPlatform)
dir, err := os.MkdirTemp("", "test_hooks_temp_dir_*")
if err != nil {
s.T().Fatalf("failed to create temp dir: %v", err)
}
s.tempDir = dir
config.WorkingPath = s.tempDir
}

func (s *AirflowHooksSuite) TearDownTest() {
os.RemoveAll(s.tempDir)
}

func (s *AirflowHooksSuite) TearDownSubTest() {
os.RemoveAll(s.tempDir)
}

var (
_ suite.SetupSubTest = (*AirflowHooksSuite)(nil)
_ suite.TearDownSubTest = (*AirflowHooksSuite)(nil)
)

func (s *AirflowHooksSuite) TestEnsureProjectDirOrInit_AlreadyProjectDir() {
s.Run("returns nil when already an Astro project directory", func() {
// Create .astro/config.yaml to mark this as a valid Astro project
astroDir := s.tempDir + "/.astro"
s.NoError(os.MkdirAll(astroDir, 0o755))
configFile, err := os.Create(astroDir + "/config.yaml")
s.NoError(err)
configFile.Close()

err = EnsureProjectDirOrInit(&cobra.Command{}, []string{})
s.NoError(err)
})
}

func (s *AirflowHooksSuite) TestEnsureProjectDirOrInit_NotProjectDir_UserConfirms() {
s.Run("initializes project when user confirms", func() {
// tempDir is not an Astro project dir; user inputs "y" to confirm init
defer testUtil.MockUserInput(s.T(), "y\n")()

err := EnsureProjectDirOrInit(&cobra.Command{}, []string{})
s.NoError(err)

// Verify the project was initialized (Dockerfile should exist)
_, statErr := os.Stat(s.tempDir + "/Dockerfile")
s.NoError(statErr, "Dockerfile should have been created by init")
})
}

func (s *AirflowHooksSuite) TestEnsureProjectDirOrInit_NotProjectDir_UserDeclines() {
s.Run("returns error when user declines initialization", func() {
// tempDir is not an Astro project dir; user inputs "n" to decline
defer testUtil.MockUserInput(s.T(), "n\n")()

err := EnsureProjectDirOrInit(&cobra.Command{}, []string{})
s.Error(err)
s.Contains(err.Error(), "this is not an Astro project directory")
})
}

func (s *AirflowHooksSuite) TestEnsureProjectDirOrInit_InvalidPath() {
s.Run("returns error when path is not resolvable", func() {
config.WorkingPath = "./\000x"

err := EnsureProjectDirOrInit(&cobra.Command{}, []string{})
s.Error(err)
s.Contains(err.Error(), "failed to verify that your working directory is an Astro project")
})
}