diff --git a/cmd/create_data_stream.go b/cmd/create_data_stream.go index 62394e3ae..8c400cd04 100644 --- a/cmd/create_data_stream.go +++ b/cmd/create_data_stream.go @@ -11,6 +11,7 @@ import ( "slices" "github.com/AlecAivazis/survey/v2" + "github.com/Masterminds/semver/v3" "github.com/spf13/cobra" @@ -19,6 +20,8 @@ import ( "github.com/elastic/elastic-package/internal/surveyext" ) +var semver3_2_0 = semver.MustParse("3.2.0") + const createDataStreamLongDescription = `Use this command to create a new data stream. The command can extend the package with a new data stream using embedded data stream template and wizard.` @@ -53,42 +56,13 @@ func createDataStreamCommandAction(cmd *cobra.Command, args []string) error { return fmt.Errorf("data-streams are not supported in input packages") } - validator := surveyext.Validator{Cwd: "."} - qs := []*survey.Question{ - { - Name: "name", - Prompt: &survey.Input{ - Message: "Data stream name:", - Default: "new_data_stream", - }, - Validate: survey.ComposeValidators(survey.Required, validator.DataStreamDoesNotExist, validator.DataStreamName), - }, - { - Name: "title", - Prompt: &survey.Input{ - Message: "Data stream title:", - Default: "New Data Stream", - }, - Validate: survey.Required, - }, - { - Name: "type", - Prompt: &survey.Select{ - Message: "Type:", - Options: []string{"logs", "metrics"}, - Default: "logs", - }, - Validate: survey.Required, - }, - { - Name: "subobjects", - Prompt: &survey.Confirm{ - Message: "Enable creation of subobjects for fields with dots in their names?", - Default: false, - }, - Validate: survey.Required, - }, + sv, err := semver.NewVersion(manifest.SpecVersion) + if err != nil { + return fmt.Errorf("failed to obtain spec version from package manifest in \"%s\": %w", packageRoot, err) } + + qs := getInitialSurveyQuestionsForVersion(sv) + var answers newDataStreamAnswers err = survey.Ask(qs, &answers) if err != nil { @@ -173,7 +147,7 @@ func createDataStreamCommandAction(cmd *cobra.Command, args []string) error { } } - descriptor := createDataStreamDescriptorFromAnswers(answers, packageRoot) + descriptor := createDataStreamDescriptorFromAnswers(answers, packageRoot, sv) err = archetype.CreateDataStream(descriptor) if err != nil { return fmt.Errorf("can't create new data stream: %w", err) @@ -183,14 +157,14 @@ func createDataStreamCommandAction(cmd *cobra.Command, args []string) error { return nil } -func createDataStreamDescriptorFromAnswers(answers newDataStreamAnswers, packageRoot string) archetype.DataStreamDescriptor { +func createDataStreamDescriptorFromAnswers(answers newDataStreamAnswers, packageRoot string, specVersion *semver.Version) archetype.DataStreamDescriptor { manifest := packages.DataStreamManifest{ Name: answers.Name, Title: answers.Title, Type: answers.Type, } - if !answers.Subobjects { + if !specVersion.LessThan(semver3_2_0) && !answers.Subobjects { manifest.Elasticsearch = &packages.Elasticsearch{ IndexTemplate: &packages.ManifestIndexTemplate{ Mappings: &packages.ManifestMappings{ @@ -231,3 +205,47 @@ func createDataStreamDescriptorFromAnswers(answers newDataStreamAnswers, package PackageRoot: packageRoot, } } + +func getInitialSurveyQuestionsForVersion(specVersion *semver.Version) []*survey.Question { + validator := surveyext.Validator{Cwd: "."} + qs := []*survey.Question{ + { + Name: "name", + Prompt: &survey.Input{ + Message: "Data stream name:", + Default: "new_data_stream", + }, + Validate: survey.ComposeValidators(survey.Required, validator.DataStreamDoesNotExist, validator.DataStreamName), + }, + { + Name: "title", + Prompt: &survey.Input{ + Message: "Data stream title:", + Default: "New Data Stream", + }, + Validate: survey.Required, + }, + { + Name: "type", + Prompt: &survey.Select{ + Message: "Type:", + Options: []string{"logs", "metrics"}, + Default: "logs", + }, + Validate: survey.Required, + }, + } + + if !specVersion.LessThan(semver3_2_0) { + qs = append(qs, &survey.Question{ + Name: "subobjects", + Prompt: &survey.Confirm{ + Message: "Enable creation of subobjects for fields with dots in their names?", + Default: false, + }, + Validate: survey.Required, + }) + } + + return qs +} diff --git a/cmd/create_data_stream_test.go b/cmd/create_data_stream_test.go new file mode 100644 index 000000000..8c25e12db --- /dev/null +++ b/cmd/create_data_stream_test.go @@ -0,0 +1,94 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package cmd + +import ( + "testing" + + "github.com/AlecAivazis/survey/v2" + "github.com/Masterminds/semver/v3" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGetSurveyQuestionsForVersion_BelowSemver3_2_0(t *testing.T) { + version := semver.MustParse("3.1.9") + questions := getInitialSurveyQuestionsForVersion(version) + + require.Len(t, questions, 3, "should return 3 questions for spec version < 3.2.0") + + assert.Equal(t, "name", questions[0].Name) + assert.IsType(t, &survey.Input{}, questions[0].Prompt) + assert.Equal(t, "title", questions[1].Name) + assert.IsType(t, &survey.Input{}, questions[1].Prompt) + assert.Equal(t, "type", questions[2].Name) + assert.IsType(t, &survey.Select{}, questions[2].Prompt) +} + +func TestGetSurveyQuestionsForVersion_EqualSemver3_2_0(t *testing.T) { + version := semver.MustParse("3.2.0") + questions := getInitialSurveyQuestionsForVersion(version) + + require.Len(t, questions, 4, "should return 4 questions for spec version >= 3.2.0") + + assert.Equal(t, "subobjects", questions[3].Name) + assert.IsType(t, &survey.Confirm{}, questions[3].Prompt) +} + +func TestGetSurveyQuestionsForVersion_AboveSemver3_2_0(t *testing.T) { + version := semver.MustParse("3.3.0") + questions := getInitialSurveyQuestionsForVersion(version) + + require.Len(t, questions, 4, "should return 4 questions for spec version > 3.2.0") + + assert.Equal(t, "subobjects", questions[3].Name) + assert.IsType(t, &survey.Confirm{}, questions[3].Prompt) +} + +func TestCreateDataStreamDescriptorFromAnswers_SubobjectsFalseForSpecVersionBelow3_2_0(t *testing.T) { + specVersion := semver.MustParse("3.1.0") + answers := newDataStreamAnswers{ + Name: "test_stream", + Title: "Test Stream", + Type: "logs", + Subobjects: false, + } + descriptor := createDataStreamDescriptorFromAnswers(answers, "/tmp/package", specVersion) + + assert.Equal(t, "test_stream", descriptor.Manifest.Name) + assert.Equal(t, "Test Stream", descriptor.Manifest.Title) + assert.Equal(t, "logs", descriptor.Manifest.Type) + assert.Equal(t, "/tmp/package", descriptor.PackageRoot) + assert.Nil(t, descriptor.Manifest.Elasticsearch) +} + +func TestCreateDataStreamDescriptorFromAnswers_SubobjectsFalseForSpecVersionGTE3_2_0(t *testing.T) { + specVersion := semver.MustParse("3.2.0") + answers := newDataStreamAnswers{ + Name: "test_stream", + Title: "Test Stream", + Type: "logs", + Subobjects: false, + } + descriptor := createDataStreamDescriptorFromAnswers(answers, "/tmp/package", specVersion) + + require.NotNil(t, descriptor.Manifest.Elasticsearch) + require.NotNil(t, descriptor.Manifest.Elasticsearch.IndexTemplate) + require.NotNil(t, descriptor.Manifest.Elasticsearch.IndexTemplate.Mappings) + assert.False(t, descriptor.Manifest.Elasticsearch.IndexTemplate.Mappings.Subobjects) +} + +func TestCreateDataStreamDescriptorFromAnswers_SubobjectsTrueForSpecVersionGTE3_2_0(t *testing.T) { + specVersion := semver.MustParse("3.2.0") + answers := newDataStreamAnswers{ + Name: "test_stream", + Title: "Test Stream", + Type: "logs", + Subobjects: true, + } + descriptor := createDataStreamDescriptorFromAnswers(answers, "/tmp/package", specVersion) + + require.Nil(t, descriptor.Manifest.Elasticsearch) +}