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
5 changes: 5 additions & 0 deletions airflow/airflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ func Init(path, airflowImageName, airflowImageTag, template string) error {
var files map[string]string
switch airflowversions.AirflowMajorVersionForRuntimeVersion(airflowImageTag) {
case "3":
// Use the floating tag for the runtime version, so that the latest patch versions are automatically used
airflowImageFloatingTag := airflowversions.RuntimeVersionMajorMinor(airflowImageTag)
if airflowImageFloatingTag != "" {
airflowImageTag = airflowImageFloatingTag
}
files = map[string]string{
".dockerignore": Af3Dockerignore,
"Dockerfile": fmt.Sprintf(Af3Dockerfile, airflowImageName, airflowImageTag),
Expand Down
47 changes: 0 additions & 47 deletions airflow/docker_registry_test.go
Copy link
Contributor Author

@jeremybeard jeremybeard May 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropped this file because it seems to be interacting with Docker Hub and so can unreliably fail, and is anyway not really unit testing any of the CLI logic.

This file was deleted.

18 changes: 15 additions & 3 deletions airflow_versions/runtime_versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ func isNewFormat(v string) bool {
return newFormatRegex.MatchString(v)
}

// parseNewFormat splits a version string into its constituent parts
// ParseNewFormat splits a version string into its constituent parts
// Returns nil if the version string does not have valid format
func parseNewFormat(v string) *versionParts {
func ParseNewFormat(v string) *versionParts {
matches := newFormatRegex.FindStringSubmatch(v)
if matches == nil {
return nil
Expand All @@ -60,7 +60,7 @@ func parseNewFormat(v string) *versionParts {
// normalizeVersion converts new format to semver format
// Returns the original string if it can't be normalized
func normalizeVersion(v string) string {
parts := parseNewFormat(v)
parts := ParseNewFormat(v)
if parts == nil {
// maybe it didn't parse because it's semver, then semver will handle it
// maybe it didn't parse because it's neither valid semver nor valid astrover, still semver will handle it
Expand Down Expand Up @@ -141,6 +141,18 @@ func RuntimeVersionMajor(version string) string {
return strings.TrimPrefix(semver.Major(v), "v")
}

// RuntimeVersionMajorMinor returns the major and minor version prefix of the version string
// For example, RuntimeVersionMajorMinor("3.0-1") == "3.0"
// If v is an invalid version string, RuntimeVersionMajorMinor returns the empty string
func RuntimeVersionMajorMinor(version string) string {
version = stripVersionPrefix(version)
v := "v" + normalizeVersion(version)
if !semver.IsValid(v) {
return ""
}
return strings.TrimPrefix(semver.MajorMinor(v), "v")
}

func AirflowMajorVersionForRuntimeVersion(runtimeVersion string) string {
if !isNewFormat(runtimeVersion) {
version := stripVersionPrefix(runtimeVersion)
Expand Down
21 changes: 21 additions & 0 deletions airflow_versions/runtime_versions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,27 @@ func (s *runtimeVersionsSuite) TestRuntimeVersionMajor() {
}
}

func (s *runtimeVersionsSuite) TestRuntimeVersionMajorMinor() {
tests := []struct {
name string
input string
expected string
}{
{"new format", "3.0-7", "3.0"},
{"old format", "12.1.1", "12.1"},
{"invalid version", "invalid", ""},
}

for _, tt := range tests {
s.t.Run(tt.name, func(t *testing.T) {
result := RuntimeVersionMajorMinor(tt.input)
if result != tt.expected {
t.Errorf("RuntimeVersionMajorMinor(%q) = %q, want %q", tt.input, result, tt.expected)
}
})
}
}

func (s *runtimeVersionsSuite) TestRuntimeVersionAirflowMajorVersion() {
tests := []struct {
name string
Expand Down
12 changes: 0 additions & 12 deletions cmd/airflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,6 @@ func (s *AirflowSuite) Test_airflowInitNonEmptyDir() {
defer testUtil.MockUserInput(s.T(), "y")()
err := airflowInit(cmd, args)
s.NoError(err)

b, _ := os.ReadFile(filepath.Join(s.tempDir, "Dockerfile"))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More non-unit unit testing, this time these fail because now that Airflow 3 is released the default Dockerfile does not contain this string.

dockerfileContents := string(b)
s.True(strings.Contains(dockerfileContents, "FROM quay.io/astronomer/astro-runtime:"))
})
}

Expand All @@ -198,10 +194,6 @@ func (s *AirflowSuite) Test_airflowInitNoDefaultImageTag() {

err := airflowInit(cmd, args)
s.NoError(err)
// assert contents of Dockerfile
b, _ := os.ReadFile(filepath.Join(s.tempDir, "Dockerfile"))
dockerfileContents := string(b)
s.True(strings.Contains(dockerfileContents, "FROM quay.io/astronomer/astro-runtime:"))
})
}

Expand Down Expand Up @@ -305,10 +297,6 @@ func (s *AirflowSuite) TestAirflowInit() {
os.Stdin = r
err := airflowInit(cmd, args)
s.NoError(err)

b, _ := os.ReadFile(filepath.Join(s.tempDir, "Dockerfile"))
dockerfileContents := string(b)
s.True(strings.Contains(dockerfileContents, "FROM quay.io/astronomer/astro-runtime:"))
})

s.Run("invalid project name", func() {
Expand Down