diff --git a/internal/question/build_steps.go b/internal/question/build_steps.go index b2fdbb8..36b62d6 100644 --- a/internal/question/build_steps.go +++ b/internal/question/build_steps.go @@ -50,6 +50,9 @@ func (q *BuildSteps) Ask(ctx context.Context) error { ) case models.Yarn, models.Npm: if answers.Type.Runtime != models.NodeJS { + if _, ok := answers.Dependencies["nodejs"]; !ok { + answers.Dependencies["nodejs"] = map[string]string{} + } answers.Dependencies["nodejs"]["n"] = "*" answers.Dependencies["nodejs"]["npx"] = "*" answers.Environment["N_PREFIX"] = "/app/.global" @@ -90,7 +93,8 @@ func (q *BuildSteps) Ask(ctx context.Context) error { } } - if answers.Stack == models.Django { + switch answers.Stack { + case models.Django: if managePyPath := utils.FindFile( path.Join(answers.WorkingDirectory, answers.ApplicationRoot), managePyFile, @@ -113,6 +117,15 @@ func (q *BuildSteps) Ask(ctx context.Context) error { fmt.Sprintf("%spython %s collectstatic --noinput", prefix, managePyPath), ) } + case models.NextJS: + // If there is no custom build script, fallback to next build for Next.js projects + if !slices.Contains(answers.BuildSteps, "yarn build") && !slices.Contains(answers.BuildSteps, "npm run build") { + cmd := "npm exec next build" + if slices.Contains(answers.DependencyManagers, models.Yarn) { + cmd = "yarn exec next build" + } + answers.BuildSteps = append(answers.BuildSteps, cmd) + } } return nil diff --git a/internal/question/build_steps_test.go b/internal/question/build_steps_test.go new file mode 100644 index 0000000..81acce6 --- /dev/null +++ b/internal/question/build_steps_test.go @@ -0,0 +1,62 @@ +package question + +import ( + "context" + "reflect" + "testing" + + "github.com/platformsh/platformify/internal/question/models" +) + +func TestBuildSteps_Ask(t *testing.T) { + type args struct { + answers models.Answers + } + tests := []struct { + name string + q *BuildSteps + args args + buildSteps []string + wantErr bool + }{ + { + name: "Next.js fallback", + q: &BuildSteps{}, + args: args{models.Answers{ + Stack: models.NextJS, + Type: models.RuntimeType{Runtime: models.NodeJS, Version: "20.0"}, + Dependencies: map[string]map[string]string{}, + DependencyManagers: []models.DepManager{models.Yarn}, + Environment: map[string]string{}, + }}, + buildSteps: []string{"yarn", "yarn exec next build"}, + wantErr: false, + }, + { + name: "Next.js npm fallback", + q: &BuildSteps{}, + args: args{models.Answers{ + Stack: models.NextJS, + Type: models.RuntimeType{Runtime: models.NodeJS, Version: "20.0"}, + Dependencies: map[string]map[string]string{}, + DependencyManagers: []models.DepManager{models.Npm}, + Environment: map[string]string{}, + }}, + buildSteps: []string{"npm i", "npm exec next build"}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + q := &BuildSteps{} + ctx := models.ToContext(context.Background(), &tt.args.answers) + if err := q.Ask(ctx); (err != nil) != tt.wantErr { + t.Errorf("BuildSteps.Ask() error = %v, wantErr %v", err, tt.wantErr) + } + + if !reflect.DeepEqual(tt.args.answers.BuildSteps, tt.buildSteps) { + t.Errorf("BuildSteps.Ask() BuildSteps = %v, want %v", tt.args.answers.BuildSteps, tt.buildSteps) + } + }) + } +}