Skip to content

Commit 11f27dd

Browse files
authored
ci: migrate e2e runner to Go (#77)
1 parent cfda671 commit 11f27dd

File tree

63 files changed

+7171
-6869
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+7171
-6869
lines changed

.github/workflows/e2e-tests.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ on:
1111
env:
1212
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
1313
CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }}
14+
CLOUDFLARE_DOMAIN: ${{ secrets.CLOUDFLARE_DOMAIN }}
1415
CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
1516
CLOUDFLARE_API_KEY: ${{ secrets.CLOUDFLARE_API_KEY }}
1617
CLOUDFLARE_R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }}
@@ -33,10 +34,7 @@ jobs:
3334
- name: Setup Terraform
3435
uses: hashicorp/setup-terraform@v3
3536
with:
36-
terraform_version: "~> 1.0"
37-
38-
- name: Build binaries
39-
run: make build-all
37+
terraform_version: "1.9.8"
4038

4139
- name: Run E2E Tests
42-
run: bin/e2e-runner run
40+
run: ./scripts/run-e2e-tests.sh --apply-exemptions

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
tf-migrate
1+
bin/
22
.terraformrc-tf-migrate
33

44
# Local provider dev overrides
@@ -25,4 +25,4 @@ e2e/tf/v4/backend.configured.hcl
2525

2626
# Backup files
2727
e2e/*.backup
28-
e2e/*.tfstate.backup
28+
e2e/*.tfstate.backup

Makefile

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,44 @@
11
# tf-migrate Makefile
22

3-
BINARY_NAME := tf-migrate
3+
BINARY_NAME := bin/tf-migrate
4+
E2E_BINARY := bin/e2e-runner
45
GO := go
56
MAIN_PACKAGE := ./cmd/tf-migrate
7+
E2E_PACKAGE := ./cmd/e2e-runner
68

7-
.PHONY: build test lint-testdata
9+
.PHONY: all build build-e2e build-all test test-e2e lint-testdata clean
810

9-
# Build the binary
11+
# Default target: build all binaries
12+
all: build-all
13+
14+
# Build the main tf-migrate binary
1015
build:
16+
@mkdir -p bin
1117
$(GO) build -v -o $(BINARY_NAME) $(MAIN_PACKAGE)
1218

13-
# Run unit tests
19+
# Build the e2e test runner binary
20+
build-e2e:
21+
@mkdir -p bin
22+
$(GO) build -v -o $(E2E_BINARY) $(E2E_PACKAGE)
23+
24+
# Build both binaries
25+
build-all: build build-e2e
26+
27+
# Run tests
1428
test:
15-
$(GO) test -v -race ./...
29+
$(GO) test -v -race ./internal/...
30+
31+
# Run e2e-runner tests only
32+
test-e2e:
33+
$(GO) test -v -race ./internal/e2e-runner
1634

1735
# Lint testdata to ensure all resources have cftftest prefix
1836
lint-testdata:
1937
@echo "Linting integration testdata for naming conventions..."
20-
@$(GO) run scripts/lint_testdata_names.go
38+
@$(GO) run scripts/lint_testdata_names.go
39+
40+
# Clean build artifacts
41+
clean:
42+
@echo "Cleaning build artifacts..."
43+
@rm -rf bin/
44+
@echo "Clean complete"

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,26 @@ E2E tests validate the complete migration workflow with real Cloudflare resource
211211
./scripts/run-e2e-tests
212212

213213
# Run E2E tests for specific resources only
214-
./scripts/run-e2e-tests --resources dns_record,api_token
214+
./scripts/run-e2e-tests --resources dns_record,api_token --apply-exemptions
215215
```
216216

217217
**Output:**
218218
- Test logs saved to `e2e/tmp/*.log`
219219
- State snapshots saved to `e2e/tmp/*-state.json`
220+
221+
**Cleaning State:**
222+
223+
If you need to remove specific modules from the remote Terraform state (useful for re-running failed tests or cleaning up partial deployments):
224+
225+
```bash
226+
# Remove specific modules from remote state
227+
./scripts/clean-state-modules.sh dns,healthcheck,zone
228+
229+
# The script will:
230+
# 1. Build the latest e2e-runner binary
231+
# 2. Pull state from R2
232+
# 3. Filter out specified modules
233+
# 4. Push cleaned state back to R2
234+
```
235+
236+
**Note:** This directly modifies the remote Terraform state. Use with caution and only in test environments.

cmd/e2e-runner/main.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strings"
7+
8+
e2e "github.com/cloudflare/tf-migrate/internal/e2e-runner"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
var rootCmd = &cobra.Command{
13+
Use: "e2e",
14+
Short: "E2E testing tool for tf-migrate",
15+
Long: `End-to-end testing framework for validating v4 to v5 migrations`,
16+
}
17+
18+
var initCmd = &cobra.Command{
19+
Use: "init",
20+
Short: "Initialize test resources",
21+
Long: `Syncs resource files from integration testdata to e2e/v4`,
22+
SilenceUsage: true, // Don't show usage on error
23+
RunE: func(cmd *cobra.Command, args []string) error {
24+
resources, _ := cmd.Flags().GetString("resources")
25+
return e2e.RunInit(resources)
26+
},
27+
}
28+
29+
var migrateCmd = &cobra.Command{
30+
Use: "migrate",
31+
Short: "Run migration from v4 to v5",
32+
Long: `Copies v4/ to migrated-v4_to_v5/ and runs migration`,
33+
SilenceUsage: true, // Don't show usage on error
34+
RunE: func(cmd *cobra.Command, args []string) error {
35+
resources, _ := cmd.Flags().GetString("resources")
36+
return e2e.RunMigrate(resources)
37+
},
38+
}
39+
40+
var runCmd = &cobra.Command{
41+
Use: "run",
42+
Short: "Run full e2e test suite",
43+
Long: `Runs the complete e2e test: init, v4 apply, migrate, v5 apply, drift check`,
44+
SilenceUsage: true, // Don't show usage on error
45+
RunE: func(cmd *cobra.Command, args []string) error {
46+
cfg := &e2e.RunConfig{
47+
SkipV4Test: cmd.Flag("skip-v4-test").Changed,
48+
ApplyExemptions: cmd.Flag("apply-exemptions").Changed,
49+
Resources: cmd.Flag("resources").Value.String(),
50+
ProviderPath: cmd.Flag("provider").Value.String(),
51+
}
52+
return e2e.RunE2ETests(cfg)
53+
},
54+
}
55+
56+
var bootstrapCmd = &cobra.Command{
57+
Use: "bootstrap",
58+
Short: "Migrate local state to R2 remote backend",
59+
Long: `One-time operation to migrate local terraform.tfstate to R2 remote backend`,
60+
SilenceUsage: true, // Don't show usage on error
61+
RunE: func(cmd *cobra.Command, args []string) error {
62+
return e2e.RunBootstrap()
63+
},
64+
}
65+
66+
var cleanCmd = &cobra.Command{
67+
Use: "clean",
68+
Short: "Remove modules from remote state",
69+
Long: `Removes specified modules from the v4 remote Terraform state in R2. Useful for cleaning up resources that have been manually deleted from Cloudflare but still exist in the Terraform state.`,
70+
SilenceUsage: true, // Don't show usage on error
71+
RunE: func(cmd *cobra.Command, args []string) error {
72+
modulesStr, _ := cmd.Flags().GetString("modules")
73+
if modulesStr == "" {
74+
return fmt.Errorf("no modules specified\nUsage: e2e clean --modules <module1,module2,...>")
75+
}
76+
modules := strings.Split(modulesStr, ",")
77+
for i := range modules {
78+
modules[i] = strings.TrimSpace(modules[i])
79+
if modules[i] == "" {
80+
return fmt.Errorf("empty module name in list")
81+
}
82+
}
83+
return e2e.RunClean(modules)
84+
},
85+
}
86+
87+
func init() {
88+
// Init command flags
89+
initCmd.Flags().String("resources", "", "Target specific resources (comma-separated)")
90+
91+
// Migrate command flags
92+
migrateCmd.Flags().String("resources", "", "Target specific resources (comma-separated)")
93+
94+
// Run command flags
95+
runCmd.Flags().Bool("skip-v4-test", false, "Skip v4 testing phase")
96+
runCmd.Flags().Bool("apply-exemptions", false, "Apply drift exemptions from e2e/drift-exemptions.yaml")
97+
runCmd.Flags().String("resources", "", "Target specific resources (comma-separated)")
98+
runCmd.Flags().String("provider", "", "Use local provider from specified path")
99+
100+
// Clean command flags
101+
cleanCmd.Flags().String("modules", "", "Modules to remove from state (comma-separated)")
102+
103+
rootCmd.AddCommand(initCmd)
104+
rootCmd.AddCommand(migrateCmd)
105+
rootCmd.AddCommand(runCmd)
106+
rootCmd.AddCommand(bootstrapCmd)
107+
rootCmd.AddCommand(cleanCmd)
108+
}
109+
110+
func main() {
111+
if err := rootCmd.Execute(); err != nil {
112+
fmt.Fprintln(os.Stderr, err)
113+
os.Exit(1)
114+
}
115+
}

e2e/README.md

Lines changed: 0 additions & 92 deletions
This file was deleted.

e2e/drift-exemptions.yaml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Drift Detection Exemptions
2+
#
3+
# This file configures which drift warnings should be ignored during e2e tests.
4+
# Use this to exempt known false positives or expected changes.
5+
6+
exemptions:
7+
# Ignore computed value refreshes (values that show as "known after apply")
8+
- name: "computed_value_refreshes"
9+
description: "Ignore attributes that refresh to 'known after apply'"
10+
patterns:
11+
- "(known after apply)"
12+
enabled: true
13+
14+
# Ignore status changes to "active" (common for DNSSEC resources)
15+
- name: "status_to_active"
16+
description: "Status changes from pending/disabled to active"
17+
resource_types:
18+
- "cloudflare_zone_dnssec"
19+
patterns:
20+
- 'status.*->.*"active"'
21+
enabled: true
22+
23+
# Example: Ignore specific resource types
24+
# - name: "zone_dnssec_computed"
25+
# description: "Ignore computed changes in zone DNSSEC resources"
26+
# resource_types:
27+
# - "cloudflare_zone_dnssec"
28+
# patterns:
29+
# - "(known after apply)"
30+
# enabled: true
31+
32+
# Example: Ignore specific attributes across all resources
33+
# - name: "last_modified_timestamps"
34+
# description: "Ignore last_modified timestamp changes"
35+
# attributes:
36+
# - "last_modified"
37+
# - "last_modified_on"
38+
# - "modified_on"
39+
# enabled: true
40+
41+
# Global settings
42+
settings:
43+
# If true, all exemptions are applied. If false, exemptions are ignored.
44+
apply_exemptions: true
45+
46+
# If true, shows which exemptions matched during drift detection
47+
verbose_exemptions: false

0 commit comments

Comments
 (0)