Skip to content

Commit 70e600c

Browse files
authored
Fix e2e v4 version (#262)
* feat: add minimum provider version check for v4→v5 migrations Add validation to ensure users are running Cloudflare Provider v4.52.5 or higher before attempting v4→v5 migrations. This version introduced critical state migration capabilities required for tf-migrate to work correctly. Features: - Check .terraform.lock.hcl for installed provider version (primary) - Fallback to required_providers version constraint in .tf files - Block migration with clear error messages if version < 4.52.5 - Add --skip-version-check flag for testing/CI scenarios - Update integration tests to use --skip-version-check Files changed: - cmd/tf-migrate/version_check.go (new) - cmd/tf-migrate/version_check_test.go (new) - cmd/tf-migrate/main.go - integration/test_runner.go - integration/v4_to_v5/phased_migration_test.go - README.md * fix e2e v4 version
1 parent 3486b1a commit 70e600c

5 files changed

Lines changed: 36 additions & 22 deletions

File tree

cmd/e2e-runner/main.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ var migrateCmd = &cobra.Command{
4646
RunE: func(cmd *cobra.Command, args []string) error {
4747
resources, _ := cmd.Flags().GetString("resources")
4848
phase, _ := cmd.Flags().GetString("phase")
49+
targetProviderVersion, _ := cmd.Flags().GetString("target-provider-version")
4950
if phase != "" {
5051
if resources != "" {
5152
return fmt.Errorf("--phase and --resources are mutually exclusive; use one or the other")
@@ -56,7 +57,7 @@ var migrateCmd = &cobra.Command{
5657
}
5758
resources = strings.Join(phaseResources, ",")
5859
}
59-
return e2e.RunMigrate(resources, false)
60+
return e2e.RunMigrate(resources, false, targetProviderVersion)
6061
},
6162
}
6263

@@ -69,14 +70,15 @@ var runCmd = &cobra.Command{
6970
parallelism, _ := cmd.Flags().GetInt("parallelism")
7071

7172
cfg := &e2e.RunConfig{
72-
SkipV4Test: cmd.Flag("skip-v4-test").Changed,
73-
ApplyExemptions: cmd.Flag("apply-exemptions").Changed,
74-
NoRefreshSnapshot: cmd.Flag("no-refresh-snapshot").Changed,
75-
Parallelism: parallelism,
76-
Resources: cmd.Flag("resources").Value.String(),
77-
Exclude: cmd.Flag("exclude").Value.String(),
78-
Phase: cmd.Flag("phase").Value.String(),
79-
ProviderPath: cmd.Flag("provider").Value.String(),
73+
SkipV4Test: cmd.Flag("skip-v4-test").Changed,
74+
ApplyExemptions: cmd.Flag("apply-exemptions").Changed,
75+
NoRefreshSnapshot: cmd.Flag("no-refresh-snapshot").Changed,
76+
Parallelism: parallelism,
77+
Resources: cmd.Flag("resources").Value.String(),
78+
Exclude: cmd.Flag("exclude").Value.String(),
79+
Phase: cmd.Flag("phase").Value.String(),
80+
ProviderPath: cmd.Flag("provider").Value.String(),
81+
TargetProviderVersion: cmd.Flag("target-provider-version").Value.String(),
8082
}
8183
return e2e.RunE2ETests(cfg)
8284
},
@@ -195,6 +197,7 @@ func init() {
195197
// Migrate command flags
196198
migrateCmd.Flags().String("resources", "", "Target specific resources (comma-separated)")
197199
migrateCmd.Flags().String("phase", "", "Run predefined phase(s) (comma-separated numbers, e.g., '0' or '0,1')")
200+
migrateCmd.Flags().String("target-provider-version", "", "Explicit provider version to set in required_providers (e.g. 5.19.0-beta.3); skips GitHub API lookup")
198201

199202
// Run command flags
200203
runCmd.Flags().Bool("skip-v4-test", false, "Skip v4 testing phase")
@@ -205,6 +208,7 @@ func init() {
205208
runCmd.Flags().String("provider", "", "Path to provider source directory (will be built automatically)")
206209
runCmd.Flags().Int("parallelism", 0, "Terraform parallelism for plan/apply (0 uses Terraform default)")
207210
runCmd.Flags().Bool("no-refresh-snapshot", false, "Run an additional diagnostic terraform plan with -refresh=false before the authoritative refresh plan")
211+
runCmd.Flags().String("target-provider-version", "", "Explicit provider version to set in required_providers (e.g. 5.19.0-beta.3); skips GitHub API lookup")
208212

209213
// Clean command flags
210214
cleanCmd.Flags().String("modules", "", "Modules to remove from state (comma-separated)")

cmd/tf-migrate/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,11 @@ func runMigration(log hclog.Logger, cfg config) error {
245245
return err
246246
}
247247

248+
// Check that the installed provider version meets minimum requirements
249+
if err := checkMinimumProviderVersion(cfg); err != nil {
250+
return err
251+
}
252+
248253
// Check for same-version migration (bypass mode)
249254
if cfg.sourceVersion == cfg.targetVersion {
250255
fmt.Printf("\n⚠ Same-version migration detected (%s → %s)\n", cfg.sourceVersion, cfg.targetVersion)

e2e/tf/v4/provider.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ terraform {
44
required_providers {
55
cloudflare = {
66
source = "cloudflare/cloudflare"
7-
version = "~> 4.0"
7+
version = "~> 4.52"
88
}
99
}
1010

internal/e2e-runner/migrate.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ import (
2121
)
2222

2323
// RunMigrate copies v4/ to migrated-v4_to_v5/ and runs migration.
24-
// When yes is true, --yes is passed to tf-migrate to auto-confirm the phase-1
24+
// When yes is true, --skip-phase-check is passed to tf-migrate to auto-confirm the phase-1
2525
// completion prompt (used for the phase-2 call in the e2e runner).
26-
func RunMigrate(resources string, yes bool) error {
26+
// targetProviderVersion is an optional explicit provider version to set in required_providers.
27+
func RunMigrate(resources string, yes bool, targetProviderVersion string) error {
2728
repoRoot := getRepoRoot()
2829
e2eRoot := filepath.Join(repoRoot, "e2e")
2930
v4Dir := filepath.Join(e2eRoot, "tf", "v4")
@@ -106,6 +107,9 @@ func RunMigrate(resources string, yes bool) error {
106107
if yes {
107108
args = append(args, "--skip-phase-check")
108109
}
110+
if targetProviderVersion != "" {
111+
args = append(args, "--target-provider-version", targetProviderVersion)
112+
}
109113

110114
cmd := exec.Command(binary, args...)
111115
cmd.Stdout = os.Stdout

internal/e2e-runner/runner.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,15 @@ const (
3333

3434
// RunConfig holds configuration for e2e test run
3535
type RunConfig struct {
36-
SkipV4Test bool
37-
ApplyExemptions bool
38-
NoRefreshSnapshot bool
39-
Parallelism int
40-
Resources string
41-
Exclude string // comma-separated resource names to exclude
42-
Phase string // comma-separated phase numbers (e.g., "0,1")
43-
ProviderPath string
36+
SkipV4Test bool
37+
ApplyExemptions bool
38+
NoRefreshSnapshot bool
39+
Parallelism int
40+
Resources string
41+
Exclude string // comma-separated resource names to exclude
42+
Phase string // comma-separated phase numbers (e.g., "0,1")
43+
ProviderPath string
44+
TargetProviderVersion string // explicit provider version to set in required_providers
4445
}
4546

4647
// testContext holds shared state for e2e test execution
@@ -313,11 +314,11 @@ func RunE2ETests(cfg *RunConfig) error {
313314
printCyan("Step 2: Running migration")
314315
printYellow("Running ./scripts/migrate...")
315316

316-
// Run the full migration directly (--yes bypasses phased migration detection).
317+
// Run the full migration directly (--skip-phase-check bypasses phased migration detection).
317318
// The e2e runner handles state cleanup itself below via terraform state rm,
318319
// which is simpler and reliable. The phased migration (_phase1_cleanup.tf)
319320
// is for real Atlantis users who cannot run terraform state rm.
320-
if err := RunMigrate(cfg.Resources, true); err != nil {
321+
if err := RunMigrate(cfg.Resources, true, cfg.TargetProviderVersion); err != nil {
321322
printError("Migration failed")
322323
return err
323324
}

0 commit comments

Comments
 (0)