diff --git a/cmd/build.go b/cmd/build.go index d5b89b9b3b..a558a4eba8 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -72,7 +72,7 @@ func buildCommandAction(cmd *cobra.Command, args []string) error { } logger.Debugf("Use build directory: %s", buildDir) - targets, err := docs.UpdateReadmes(packageRoot) + targets, err := docs.UpdateReadmes(packageRoot, buildDir) if err != nil { return fmt.Errorf("updating files failed: %w", err) } @@ -84,6 +84,7 @@ func buildCommandAction(cmd *cobra.Command, args []string) error { target, err := builder.BuildPackage(cmd.Context(), builder.BuildOptions{ PackageRoot: packageRoot, + BuildDir: buildDir, CreateZip: createZip, SignPackage: signPackage, SkipValidation: skipValidation, diff --git a/internal/builder/packages.go b/internal/builder/packages.go index cb88f4de57..c3096d25c3 100644 --- a/internal/builder/packages.go +++ b/internal/builder/packages.go @@ -20,13 +20,14 @@ import ( "github.com/elastic/elastic-package/internal/validation" ) -const builtPackagesFolder = "packages" +const builtPackagesDir = "packages" const licenseTextFileName = "LICENSE.txt" var repositoryLicenseEnv = environment.WithElasticPackagePrefix("REPOSITORY_LICENSE") type BuildOptions struct { PackageRoot string + BuildDir string CreateZip bool SignPackage bool @@ -73,10 +74,28 @@ func findBuildDirectory() (string, bool, error) { } // BuildPackagesDirectory function locates the target build directory for the package. -func BuildPackagesDirectory(packageRoot string) (string, error) { - buildDir, err := buildPackagesRootDirectory() - if err != nil { - return "", fmt.Errorf("can't locate build packages root directory: %w", err) +// It is in the form /packages//. +func BuildPackagesDirectory(packageRoot string, buildDir string) (string, error) { + if buildDir == "" { + d, err := buildPackagesRootDirectory() + if err != nil { + return "", fmt.Errorf("can't locate build packages root directory: %w", err) + } + buildDir = d + } else { + info, err := os.Stat(buildDir) + if err != nil { + return "", fmt.Errorf("can't check build directory: %w", err) + } + if !info.IsDir() { + return "", fmt.Errorf("build path (%s) expected to be a directory", err) + } + d := filepath.Join(buildDir, builtPackagesDir) + err = os.MkdirAll(d, 0755) + if err != nil { + return "", err + } + buildDir = d } m, err := packages.ReadPackageManifestFromPackageRoot(packageRoot) if err != nil { @@ -109,7 +128,7 @@ func buildPackagesRootDirectory() (string, error) { return "", fmt.Errorf("can't locate build directory: %w", err) } if !found { - buildDir, err = createBuildDirectory(builtPackagesFolder) + buildDir, err = createBuildDirectory(builtPackagesDir) if err != nil { return "", fmt.Errorf("can't create new build directory: %w", err) } @@ -125,7 +144,7 @@ func FindBuildPackagesDirectory() (string, bool, error) { } if found { - path := filepath.Join(buildDir, builtPackagesFolder) + path := filepath.Join(buildDir, builtPackagesDir) fileInfo, err := os.Stat(path) if errors.Is(err, os.ErrNotExist) { return "", false, nil @@ -144,7 +163,7 @@ func FindBuildPackagesDirectory() (string, bool, error) { // BuildPackage function builds the package. func BuildPackage(ctx context.Context, options BuildOptions) (string, error) { - destinationDir, err := BuildPackagesDirectory(options.PackageRoot) + destinationDir, err := BuildPackagesDirectory(options.PackageRoot, options.BuildDir) if err != nil { return "", fmt.Errorf("can't locate build directory: %w", err) } diff --git a/internal/docs/readme.go b/internal/docs/readme.go index 256b7d2d9e..817585926f 100644 --- a/internal/docs/readme.go +++ b/internal/docs/readme.go @@ -94,7 +94,7 @@ func isReadmeUpToDate(fileName, packageRoot string) (bool, string, error) { // UpdateReadmes function updates all .md readme files using a defined template // files. The function doesn't perform any action if the template file is not present. -func UpdateReadmes(packageRoot string) ([]string, error) { +func UpdateReadmes(packageRoot, buildDir string) ([]string, error) { readmeFiles, err := filepath.Glob(filepath.Join(packageRoot, "_dev", "build", "docs", "*.md")) if err != nil { return nil, fmt.Errorf("reading directory entries failed: %w", err) @@ -103,7 +103,7 @@ func UpdateReadmes(packageRoot string) ([]string, error) { var targets []string for _, filePath := range readmeFiles { fileName := filepath.Base(filePath) - target, err := updateReadme(fileName, packageRoot) + target, err := updateReadme(fileName, packageRoot, buildDir) if err != nil { return nil, fmt.Errorf("updating readme file %s failed: %w", fileName, err) } @@ -115,7 +115,7 @@ func UpdateReadmes(packageRoot string) ([]string, error) { return targets, nil } -func updateReadme(fileName, packageRoot string) (string, error) { +func updateReadme(fileName, packageRoot, buildDir string) (string, error) { logger.Debugf("Update the %s file", fileName) rendered, shouldBeRendered, err := generateReadme(fileName, packageRoot) @@ -131,7 +131,7 @@ func updateReadme(fileName, packageRoot string) (string, error) { return "", fmt.Errorf("writing %s file failed: %w", fileName, err) } - packageBuildRoot, err := builder.BuildPackagesDirectory(packageRoot) + packageBuildRoot, err := builder.BuildPackagesDirectory(packageRoot, buildDir) if err != nil { return "", fmt.Errorf("package build root not found: %w", err) } diff --git a/internal/packages/archetype/data_stream_test.go b/internal/packages/archetype/data_stream_test.go index 700abcd418..30b124f5ed 100644 --- a/internal/packages/archetype/data_stream_test.go +++ b/internal/packages/archetype/data_stream_test.go @@ -5,7 +5,6 @@ package archetype import ( - "os" "path/filepath" "testing" @@ -59,19 +58,8 @@ func createDataStreamDescriptorForTest() DataStreamDescriptor { } func createAndCheckDataStream(t *testing.T, pd PackageDescriptor, dd DataStreamDescriptor, valid bool) { - wd, err := os.Getwd() - require.NoError(t, err) - - tempDir, err := os.MkdirTemp("", "archetype-create-data-stream-") - require.NoError(t, err) - - os.Chdir(tempDir) - defer func() { - os.Chdir(wd) - os.RemoveAll(tempDir) - }() - - err = CreatePackage(pd) + tempDir := makeInRepoBuildTempDir(t) + err := createPackageInDir(pd, tempDir) require.NoError(t, err) packageRoot := filepath.Join(tempDir, pd.Manifest.Name) @@ -80,5 +68,5 @@ func createAndCheckDataStream(t *testing.T, pd PackageDescriptor, dd DataStreamD err = CreateDataStream(dd) require.NoError(t, err) - checkPackage(t, pd.Manifest.Name, valid) + checkPackage(t, packageRoot, valid) } diff --git a/internal/packages/archetype/package_test.go b/internal/packages/archetype/package_test.go index 6daabf2007..1cfdaffb64 100644 --- a/internal/packages/archetype/package_test.go +++ b/internal/packages/archetype/package_test.go @@ -5,14 +5,17 @@ package archetype import ( + "context" + "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/elastic/elastic-package/internal/builder" + "github.com/elastic/elastic-package/internal/docs" "github.com/elastic/elastic-package/internal/packages" - "github.com/elastic/elastic-package/internal/validation" ) func TestPackage(t *testing.T) { @@ -36,7 +39,7 @@ func TestPackage(t *testing.T) { } func createAndCheckPackage(t *testing.T, pd PackageDescriptor, valid bool) { - tempDir := t.TempDir() + tempDir := makeInRepoBuildTempDir(t) err := createPackageInDir(pd, tempDir) require.NoError(t, err) @@ -90,8 +93,22 @@ func createPackageDescriptorForTest(packageType, kibanaVersion string) PackageDe } } +func buildPackage(t *testing.T, packageRoot string) error { + buildDir := makeInRepoBuildTempDir(t) + _, err := docs.UpdateReadmes(packageRoot, buildDir) + if err != nil { + return err + } + + _, err = builder.BuildPackage(context.Background(), builder.BuildOptions{ + PackageRoot: packageRoot, + BuildDir: buildDir, + }) + return err +} + func checkPackage(t *testing.T, packageRoot string, valid bool) { - err, _ := validation.ValidateAndFilterFromPath(packageRoot) + err := buildPackage(t, packageRoot) if !valid { assert.Error(t, err) return @@ -124,3 +141,22 @@ func checkPackage(t *testing.T, packageRoot string, valid bool) { }) } } + +// makeInRepoBuildTempDir mimicks t.TempDir(), but creates the directory inside the current +// directory. +// FIXME: It should be possible to use t.TempDir(), but conflicts with links resolution, as +// t.TempDir() creates the directory out of the repository. We should refactor links resolution +// so it can write files out of the repository. +// https://github.com/elastic/elastic-package/issues/2797 +func makeInRepoBuildTempDir(t *testing.T) string { + t.Helper() + cwd, err := os.Getwd() + require.NoError(t, err) + dir, err := os.MkdirTemp(cwd, "_build-test-*") + require.NoError(t, err) + t.Cleanup(func() { + err := os.RemoveAll(dir) + assert.NoError(t, err) + }) + return dir +}