Skip to content

Commit 27fa719

Browse files
authored
chore: rename migrate to convert (#625)
1 parent a568daf commit 27fa719

File tree

3 files changed

+62
-69
lines changed

3 files changed

+62
-69
lines changed
Lines changed: 36 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net/http"
1010
"os"
1111
"path/filepath"
12+
"slices"
1213
"strings"
1314
"time"
1415

@@ -18,15 +19,15 @@ import (
1819
"github.com/buildkite/cli/v3/pkg/cmd/factory"
1920
)
2021

21-
var MigrationEndpoint = "https://m4vrh5pvtd.execute-api.us-east-1.amazonaws.com/production/migrate"
22+
var convertEndpoint = "https://m4vrh5pvtd.execute-api.us-east-1.amazonaws.com/production/migrate"
2223

23-
type migrationRequest struct {
24+
type conversionRequest struct {
2425
Vendor string `json:"vendor"`
2526
Code string `json:"code"`
2627
AI bool `json:"ai,omitempty"`
2728
}
2829

29-
type migrationResponse struct {
30+
type conversionResponse struct {
3031
JobID string `json:"jobId"`
3132
Status string `json:"status"`
3233
Message string `json:"message"`
@@ -43,16 +44,16 @@ type statusResponse struct {
4344
Error string `json:"error,omitempty"`
4445
}
4546

46-
type MigrateCmd struct {
47-
File string `help:"Path to the pipeline file to migrate (required)" short:"F" required:""`
47+
type ConvertCmd struct {
48+
File string `help:"Path to the pipeline file to convert (required)" short:"F" required:""`
4849
Vendor string `help:"CI/CD vendor (auto-detected if not specified)" short:"v"`
49-
AI bool `help:"Use AI-powered migration (recommended for Jenkins)"`
50-
Output string `help:"Custom path to save the migrated pipeline (default: .buildkite/pipeline.<vendor>.yml)" short:"o"`
51-
Timeout int `help:"Timeout in seconds (use 600+ for AI migrations)" default:"300"`
50+
AI bool `help:"Use AI-powered conversion (recommended for Jenkins)"`
51+
Output string `help:"Custom path to save the converted pipeline (default: .buildkite/pipeline.<vendor>.yml)" short:"o"`
52+
Timeout int `help:"Timeout in seconds (use 600+ for AI conversions)" default:"300"`
5253
}
5354

54-
func (c *MigrateCmd) Help() string {
55-
return `Migrate a CI/CD pipeline configuration from various vendors to Buildkite format.
55+
func (c *ConvertCmd) Help() string {
56+
return `Convert a CI/CD pipeline configuration from various vendors to Buildkite format.
5657
5758
Supported vendors:
5859
- github (GitHub Actions)
@@ -62,27 +63,27 @@ Supported vendors:
6263
6364
The command will automatically detect the vendor based on the file name if not specified.
6465
65-
By default, the migrated pipeline is saved to .buildkite/pipeline.<vendor>.yml.
66+
By default, the converted pipeline is saved to .buildkite/pipeline.<vendor>.yml.
6667
Use the --output flag to specify a custom output path.
6768
68-
Note: This command does not require an API token since it uses a public migration API.
69+
Note: This command does not require an API token since it uses a public conversion API.
6970
7071
Examples:
71-
# Migrate a GitHub Actions workflow
72-
$ bk pipeline migrate -F .github/workflows/ci.yml
72+
# Convert a GitHub Actions workflow
73+
$ bk pipeline convert -F .github/workflows/ci.yml
7374
74-
# Migrate with explicit vendor specification
75-
$ bk pipeline migrate -F pipeline.yml --vendor circleci
75+
# Convert with explicit vendor specification
76+
$ bk pipeline convert -F pipeline.yml --vendor circleci
7677
77-
# Migrate Jenkins pipeline with AI support
78-
$ bk pipeline migrate -F Jenkinsfile --ai
78+
# Convert Jenkins pipeline with AI support
79+
$ bk pipeline convert -F Jenkinsfile --ai
7980
8081
# Save output to a file
81-
$ bk pipeline migrate -F .github/workflows/ci.yml -o .buildkite/pipeline.yml
82+
$ bk pipeline convert -F .github/workflows/ci.yml -o .buildkite/pipeline.yml
8283
`
8384
}
8485

85-
func (c *MigrateCmd) Run(kongCtx *kong.Context, globals cli.GlobalFlags) error {
86+
func (c *ConvertCmd) Run(kongCtx *kong.Context, globals cli.GlobalFlags) error {
8687
f, err := factory.New(factory.WithDebug(globals.EnableDebug()))
8788
if err != nil {
8889
return err
@@ -106,46 +107,46 @@ func (c *MigrateCmd) Run(kongCtx *kong.Context, globals cli.GlobalFlags) error {
106107
}
107108

108109
supportedVendors := []string{"github", "bitbucket", "circleci", "jenkins"}
109-
if !contains(supportedVendors, c.Vendor) {
110+
if !slices.Contains(supportedVendors, c.Vendor) {
110111
return fmt.Errorf("unsupported vendor: %s (supported: %s)", c.Vendor, strings.Join(supportedVendors, ", "))
111112
}
112113

113-
req := migrationRequest{
114+
req := conversionRequest{
114115
Vendor: c.Vendor,
115116
Code: string(content),
116117
AI: c.AI,
117118
}
118119

119-
fmt.Println("Submitting migration job...")
120+
fmt.Println("Submitting conversion job...")
120121

121-
jobResp, err := submitMigrationJob(req)
122+
jobResp, err := submitConversionJob(req)
122123
if err != nil {
123-
return fmt.Errorf("error submitting migration job: %w", err)
124+
return fmt.Errorf("error submitting conversion job: %w", err)
124125
}
125126

126127
if c.AI {
127128
fmt.Println("Job submitted. Processing with AI (this may take several minutes)...")
128129
} else {
129-
fmt.Println("Job submitted. Processing migration...")
130+
fmt.Println("Job submitted. Processing conversion...")
130131
}
131132

132133
var result *statusResponse
133-
err = bkIO.SpinWhile(f, "Processing migration...", func() {
134+
err = bkIO.SpinWhile(f, "Processing conversion...", func() {
134135
result, err = pollJobStatus(jobResp.JobID, c.Timeout)
135136
})
136137
if err != nil {
137138
return fmt.Errorf("error polling job status: %w", err)
138139
}
139140

140141
if result.Status == "failed" {
141-
return fmt.Errorf("migration failed: %s", result.Error)
142+
return fmt.Errorf("conversion failed: %s", result.Error)
142143
}
143144

144145
if c.Output != "" {
145146
if err := os.WriteFile(c.Output, []byte(result.Result), 0o644); err != nil {
146147
return fmt.Errorf("error writing output file: %w", err)
147148
}
148-
fmt.Printf("\nMigration completed successfully!\n")
149+
fmt.Printf("\nconversion completed successfully!\n")
149150
fmt.Printf("Output saved to: %s\n", c.Output)
150151
} else {
151152
buildkiteDir := ".buildkite"
@@ -160,7 +161,7 @@ func (c *MigrateCmd) Run(kongCtx *kong.Context, globals cli.GlobalFlags) error {
160161
return fmt.Errorf("error writing output file: %w", err)
161162
}
162163

163-
fmt.Printf("\nMigration completed successfully!\n")
164+
fmt.Printf("\nconversion completed successfully!\n")
164165
fmt.Printf("Output saved to: %s\n", defaultOutputPath)
165166
}
166167

@@ -189,22 +190,13 @@ func detectVendor(filePath string) (string, error) {
189190
return "", fmt.Errorf("could not detect vendor from file path. Please specify vendor explicitly with --vendor")
190191
}
191192

192-
func contains(slice []string, str string) bool {
193-
for _, s := range slice {
194-
if s == str {
195-
return true
196-
}
197-
}
198-
return false
199-
}
200-
201-
func submitMigrationJob(req migrationRequest) (*migrationResponse, error) {
193+
func submitConversionJob(req conversionRequest) (*conversionResponse, error) {
202194
reqBody, err := json.Marshal(req)
203195
if err != nil {
204196
return nil, fmt.Errorf("error marshaling request: %w", err)
205197
}
206198

207-
httpReq, err := http.NewRequestWithContext(context.Background(), "POST", MigrationEndpoint, bytes.NewReader(reqBody))
199+
httpReq, err := http.NewRequestWithContext(context.Background(), "POST", convertEndpoint, bytes.NewReader(reqBody))
208200
if err != nil {
209201
return nil, fmt.Errorf("error creating request: %w", err)
210202
}
@@ -227,7 +219,7 @@ func submitMigrationJob(req migrationRequest) (*migrationResponse, error) {
227219
return nil, fmt.Errorf("API request failed (status %d): %s", resp.StatusCode, string(body))
228220
}
229221

230-
var jobResp migrationResponse
222+
var jobResp conversionResponse
231223
if err := json.Unmarshal(body, &jobResp); err != nil {
232224
return nil, fmt.Errorf("error parsing response: %w", err)
233225
}
@@ -236,7 +228,7 @@ func submitMigrationJob(req migrationRequest) (*migrationResponse, error) {
236228
}
237229

238230
func pollJobStatus(jobID string, timeoutSeconds int) (*statusResponse, error) {
239-
statusURL := fmt.Sprintf("%s/%s/status", MigrationEndpoint, jobID)
231+
statusURL := fmt.Sprintf("%s/%s/status", convertEndpoint, jobID)
240232
client := &http.Client{Timeout: 30 * time.Second}
241233

242234
maxAttempts := timeoutSeconds / 5
@@ -281,5 +273,5 @@ func pollJobStatus(jobID string, timeoutSeconds int) (*statusResponse, error) {
281273
}
282274
}
283275

284-
return nil, fmt.Errorf("migration timed out after %d seconds", timeoutSeconds)
276+
return nil, fmt.Errorf("conversion timed out after %d seconds", timeoutSeconds)
285277
}
Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import (
66
"net/http/httptest"
77
"os"
88
"path/filepath"
9+
"slices"
910
"strings"
1011
"testing"
1112
"time"
1213
)
1314

14-
func TestMigrationAPIEndpoint(t *testing.T) {
15+
func TestConversionAPIEndpoint(t *testing.T) {
1516
if testing.Short() {
1617
t.Skip("Skipping integration test in short mode")
1718
}
@@ -27,16 +28,16 @@ jobs:
2728
- run: echo "Hello World"
2829
`
2930

30-
// Submit a migration job
31-
req := migrationRequest{
31+
// Submit a Conversion job
32+
req := conversionRequest{
3233
Vendor: "github",
3334
Code: testWorkflow,
3435
AI: false,
3536
}
3637

37-
jobResp, err := submitMigrationJob(req)
38+
jobResp, err := submitConversionJob(req)
3839
if err != nil {
39-
t.Fatalf("Migration API endpoint is not accessible or broken. This will break the CLI for users. Error: %v", err)
40+
t.Fatalf("Conversion API endpoint is not accessible or broken. This will break the CLI for users. Error: %v", err)
4041
}
4142

4243
if jobResp.JobID == "" {
@@ -54,7 +55,7 @@ jobs:
5455
}
5556

5657
if result.Status == "failed" {
57-
t.Errorf("Migration failed: %s", result.Error)
58+
t.Errorf("Conversion failed: %s", result.Error)
5859
}
5960

6061
if result.Status != "completed" {
@@ -188,15 +189,15 @@ func TestContains(t *testing.T) {
188189
t.Run(tt.name, func(t *testing.T) {
189190
t.Parallel()
190191

191-
got := contains(tt.slice, tt.str)
192+
got := slices.Contains(tt.slice, tt.str)
192193
if got != tt.want {
193194
t.Errorf("Expected %v, got %v", tt.want, got)
194195
}
195196
})
196197
}
197198
}
198199

199-
func TestSubmitMigrationJob(t *testing.T) {
200+
func TestSubmitConversionJob(t *testing.T) {
200201
t.Parallel()
201202

202203
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -208,7 +209,7 @@ func TestSubmitMigrationJob(t *testing.T) {
208209
t.Errorf("Expected Content-Type: application/json, got %s", r.Header.Get("Content-Type"))
209210
}
210211

211-
var req migrationRequest
212+
var req conversionRequest
212213
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
213214
t.Errorf("Failed to decode request body: %v", err)
214215
w.WriteHeader(http.StatusBadRequest)
@@ -221,10 +222,10 @@ func TestSubmitMigrationJob(t *testing.T) {
221222
return
222223
}
223224

224-
resp := migrationResponse{
225+
resp := conversionResponse{
225226
JobID: "test-job-123",
226227
Status: "processing",
227-
Message: "Migration job queued for processing",
228+
Message: "Conversion job queued for processing",
228229
StatusURL: "https://example.com/migrate/test-job-123/status",
229230
}
230231

@@ -234,19 +235,19 @@ func TestSubmitMigrationJob(t *testing.T) {
234235
}))
235236
defer server.Close()
236237

237-
originalEndpoint := MigrationEndpoint
238-
MigrationEndpoint = server.URL
239-
defer func() { MigrationEndpoint = originalEndpoint }()
238+
originalEndpoint := convertEndpoint
239+
convertEndpoint = server.URL
240+
defer func() { convertEndpoint = originalEndpoint }()
240241

241-
req := migrationRequest{
242+
req := conversionRequest{
242243
Vendor: "github",
243244
Code: "name: Test\non: [push]",
244245
AI: false,
245246
}
246247

247-
resp, err := submitMigrationJob(req)
248+
resp, err := submitConversionJob(req)
248249
if err != nil {
249-
t.Fatalf("Failed to submit migration job: %v", err)
250+
t.Fatalf("Failed to submit Conversion job: %v", err)
250251
}
251252

252253
if resp.JobID != "test-job-123" {
@@ -291,9 +292,9 @@ func TestPollJobStatus(t *testing.T) {
291292
}))
292293
defer server.Close()
293294

294-
originalEndpoint := MigrationEndpoint
295-
MigrationEndpoint = server.URL
296-
defer func() { MigrationEndpoint = originalEndpoint }()
295+
originalEndpoint := convertEndpoint
296+
convertEndpoint = server.URL
297+
defer func() { convertEndpoint = originalEndpoint }()
297298

298299
result, err := pollJobStatus("test-job-123", 30)
299300
if err != nil {
@@ -326,9 +327,9 @@ func TestPollJobStatusTimeout(t *testing.T) {
326327
}))
327328
defer server.Close()
328329

329-
originalEndpoint := MigrationEndpoint
330-
MigrationEndpoint = server.URL
331-
defer func() { MigrationEndpoint = originalEndpoint }()
330+
originalEndpoint := convertEndpoint
331+
convertEndpoint = server.URL
332+
defer func() { convertEndpoint = originalEndpoint }()
332333

333334
_, err := pollJobStatus("test-job-123", 5)
334335
if err == nil {
@@ -343,7 +344,7 @@ func TestPollJobStatusTimeout(t *testing.T) {
343344
func TestMigrateCommandCreation(t *testing.T) {
344345
t.Parallel()
345346

346-
cmd := &MigrateCmd{
347+
cmd := &ConvertCmd{
347348
File: "test.yml",
348349
Vendor: "github",
349350
Timeout: 300,

main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ type (
9797
Copy pipeline.CopyCmd `cmd:"" help:"Copy an existing pipeline." aliases:"cp"`
9898
Create pipeline.CreateCmd `cmd:"" help:"Create a new pipeline."`
9999
List pipeline.ListCmd `cmd:"" help:"List pipelines." aliases:"ls"`
100-
Migrate pipeline.MigrateCmd `cmd:"" help:"Migrate a CI/CD pipeline configuration to Buildkite format."`
100+
Convert pipeline.ConvertCmd `cmd:"" help:"Convert a CI/CD pipeline configuration to Buildkite format." aliases:"migrate"`
101101
Validate pipeline.ValidateCmd `cmd:"" help:"Validate a pipeline YAML file."`
102102
View pipeline.ViewCmd `cmd:"" help:"View a pipeline."`
103103
}

0 commit comments

Comments
 (0)