diff --git a/bitrise.yml b/bitrise.yml index 4da805c4..f7b5d6c9 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -269,7 +269,7 @@ workflows: inputs: - content: |- set -exo pipefail - ../bitrise-build-cache-cli enable-for gradle --metrics -d + ../bitrise-build-cache-cli activate gradle -d --cache - script: title: Build and capture logs inputs: @@ -299,7 +299,7 @@ workflows: inputs: - content: |- set -exo pipefail - ../bitrise-build-cache-cli enable-for gradle --metrics -d + ../bitrise-build-cache-cli activate gradle -d --cache - script: title: Create local configuration cache inputs: @@ -406,7 +406,7 @@ workflows: inputs: - content: |- set -exo pipefail - ../bitrise-build-cache-cli enable-for gradle --metrics -d + ../bitrise-build-cache-cli activate gradle -d --cache - script: title: Create local configuration cache inputs: @@ -465,7 +465,7 @@ workflows: inputs: - content: |- set -exo pipefail - ../bitrise-build-cache-cli enable-for gradle --metrics -d + ../bitrise-build-cache-cli activate gradle -d --cache - script: title: Create local configuration cache inputs: diff --git a/cmd/activate.go b/cmd/activate.go new file mode 100644 index 00000000..9ed36e16 --- /dev/null +++ b/cmd/activate.go @@ -0,0 +1,17 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +// activateCmd represents the activate command +var activateCmd = &cobra.Command{ //nolint:gochecknoglobals + Use: "activate", + Short: "Activate various bitrise plugins", + Long: `Activate Gradle, Bazel, etc. plugins +Call the subcommands with the name of the tool you want to activate plugins for.`, +} + +func init() { + rootCmd.AddCommand(activateCmd) +} diff --git a/cmd/activate_for_gradle.go b/cmd/activate_for_gradle.go new file mode 100644 index 00000000..5df1967d --- /dev/null +++ b/cmd/activate_for_gradle.go @@ -0,0 +1,116 @@ +package cmd + +import ( + "fmt" + "os" + + gradleconfig "github.com/bitrise-io/bitrise-build-cache-cli/internal/config/gradle" + "github.com/bitrise-io/go-utils/v2/log" + "github.com/bitrise-io/go-utils/v2/pathutil" + "github.com/spf13/cobra" +) + +const ( + errFmtFailedToUpdateProps = `failed to update gradle.properties: %w"` +) + +// activateForGradleCmd represents the `gradle` subcommand under `activate` +var activateForGradleCmd = &cobra.Command{ //nolint:gochecknoglobals + Use: "gradle", + Short: "Activate Bitrise Plugins for Gradle", + Long: `Activate Bitrise Plugins for Gradle. +This command will: + +- Create a ~/.gradle/init.d/bitrise-build-cache.init.gradle.kts file with the necessary configs. This file will be overwritten. +- Create a ~/.gradle/gradle.properties file with org.gradle.caching=true when adding the caching plugin. + +The gradle.properties file will be created if it doesn't exist. +If it already exists a "# [start/end] generated-by-bitrise-build-cache" block will be added to the end of the file. +If the "# [start/end] generated-by-bitrise-build-cache" block is already present in the file then only the block's content will be modified. +`, + SilenceUsage: true, + RunE: func(cmd *cobra.Command, _ []string) error { + logger := log.NewLogger() + logger.EnableDebugLog(isDebugLogMode) + logger.TInfof("Activate Bitrise plugins for Gradle") + + gradleHome, err := pathutil.NewPathModifier().AbsPath(gradleHomeNonExpanded) + if err != nil { + return fmt.Errorf("expand Gradle home path (%s), error: %w", gradleHome, err) + } + + if err := getPlugins(cmd.Context(), logger, os.Getenv); err != nil { + return fmt.Errorf("failed to fetch plugins: %w", err) + } + + if err := activateForGradleCmdFn( + logger, + gradleHome, + os.Getenv, + activateForGradleParams.TemplateInventory, + func( + inventory gradleconfig.TemplateInventory, + path string, + ) error { + return inventory.WriteToGradleInit( + logger, + path, + gradleconfig.DefaultOsProxy(), + gradleconfig.DefaultTemplateProxy(), + ) + }, + gradleconfig.DefaultGradlePropertiesUpdater(), + ); err != nil { + return fmt.Errorf("activate plugins for Gradle: %w", err) + } + + logger.TInfof("✅ Bitrise plugins activated") + + return nil + }, +} + +//nolint:gochecknoglobals +var activateForGradleParams = gradleconfig.DefaultActivateForGradleParams() + +func init() { + activateCmd.AddCommand(activateForGradleCmd) + activateForGradleCmd.Flags().BoolVar(&activateForGradleParams.Cache.Enabled, "cache", activateForGradleParams.Cache.Enabled, "Activate cache plugin. Will override cache-dep.") + activateForGradleCmd.Flags().BoolVar(&activateForGradleParams.Cache.JustDependency, "cache-dep", activateForGradleParams.Cache.JustDependency, "Add cache plugin as a dependency only.") + activateForGradleCmd.Flags().BoolVar(&activateForGradleParams.Cache.PushEnabled, "cache-push", activateForGradleParams.Cache.PushEnabled, "Push enabled/disabled. Enabled means the build can also write new entries to the remote cache. Disabled means the build can only read from the remote cache.") + activateForGradleCmd.Flags().StringVar(&activateForGradleParams.Cache.ValidationLevel, "cache-validation", activateForGradleParams.Cache.ValidationLevel, "Level of cache entry validation for both uploads and downloads. Possible values: none, warning, error") + activateForGradleCmd.Flags().StringVar(&activateForGradleParams.Cache.Endpoint, "cache-endpoint", activateForGradleParams.Cache.Endpoint, "The endpoint can be manually provided here for caching operations.") + + activateForGradleCmd.Flags().BoolVar(&activateForGradleParams.Analytics.Enabled, "analytics", activateForGradleParams.Analytics.Enabled, "Activate analytics plugin. Will override analytics-dep.") + activateForGradleCmd.Flags().BoolVar(&activateForGradleParams.Analytics.JustDependency, "analytics-dep", activateForGradleParams.Analytics.JustDependency, "Add analytics plugin as a dependency only.") + + activateForGradleCmd.Flags().BoolVar(&activateForGradleParams.TestDistro.Enabled, "test-distribution", activateForGradleParams.TestDistro.Enabled, "Activate test distribution plugin for the provided app slug. Will override test-distribution-dep.") + activateForGradleCmd.Flags().BoolVar(&activateForGradleParams.TestDistro.JustDependency, "test-distribution-dep", activateForGradleParams.TestDistro.JustDependency, "Add test distribution plugin as a dependency only.") +} + +func activateForGradleCmdFn( + logger log.Logger, + gradleHomePath string, + envProvider func(string) string, + templateInventoryProvider func(log.Logger, func(string) string, bool) (gradleconfig.TemplateInventory, error), + templateWriter func(gradleconfig.TemplateInventory, string) error, + updater gradleconfig.GradlePropertiesUpdater, +) error { + templateInventory, err := templateInventoryProvider(logger, envProvider, isDebugLogMode) + if err != nil { + return err + } + + if err := templateWriter( + templateInventory, + gradleHomePath, + ); err != nil { + return err + } + + if err := updater.UpdateGradleProps(activateForGradleParams, logger, gradleHomePath); err != nil { + return fmt.Errorf(errFmtFailedToUpdateProps, err) + } + + return nil +} diff --git a/cmd/activate_for_gradle_cmd_test.go b/cmd/activate_for_gradle_cmd_test.go new file mode 100644 index 00000000..7949f2a2 --- /dev/null +++ b/cmd/activate_for_gradle_cmd_test.go @@ -0,0 +1,181 @@ +//nolint:dupl +package cmd + +import ( + "errors" + "fmt" + "os" + "testing" + + gradleconfig "github.com/bitrise-io/bitrise-build-cache-cli/internal/config/gradle" + "github.com/bitrise-io/go-utils/v2/log" + "github.com/bitrise-io/go-utils/v2/mocks" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func Test_activateForGradleCmdFn(t *testing.T) { + prep := func() log.Logger { + mockLogger := &mocks.Logger{} + mockLogger.On("Infof", mock.Anything).Return() + mockLogger.On("Infof", mock.Anything, mock.Anything).Return() + mockLogger.On("Debugf", mock.Anything).Return() + mockLogger.On("Debugf", mock.Anything, mock.Anything).Return() + mockLogger.On("Errorf", mock.Anything).Return() + mockLogger.On("Errorf", mock.Anything, mock.Anything).Return() + + return mockLogger + } + + t.Run("activateForGradleCmdFn", func(t *testing.T) { + mockLogger := prep() + templateInventory := gradleconfig.TemplateInventory{ + Common: gradleconfig.PluginCommonTemplateInventory{ + AppSlug: "AppSlugValue", + }, + } + + var actualTemplateInventory *gradleconfig.TemplateInventory + var actualPath *string + + // when + err := activateForGradleCmdFn( + mockLogger, + "~/.gradle", + func(string) string { return "" }, + func(log.Logger, func(string) string, bool) (gradleconfig.TemplateInventory, error) { + return templateInventory, nil + }, + func( + inventory gradleconfig.TemplateInventory, + _ string, + ) error { + actualTemplateInventory = &inventory + + return nil + }, + gradleconfig.GradlePropertiesUpdater{ + OsProxy: gradleconfig.OsProxy{ + ReadFileIfExists: func(pth string) (string, bool, error) { + actualPath = &pth + + return "", true, nil + }, + WriteFile: func(string, []byte, os.FileMode) error { return nil }, + }, + }, + ) + + // then + require.NoError(t, err) + require.Equal(t, templateInventory, *actualTemplateInventory) + require.Equal(t, "~/.gradle/gradle.properties", *actualPath) + }) + + t.Run("when templateInventory creation fails activateForGradleCmdFn throws error", func(t *testing.T) { + mockLogger := prep() + inventoryCreationError := errors.New("failed to create inventory") + + // when + err := activateForGradleCmdFn( + mockLogger, + "~/.gradle", + func(string) string { return "" }, + func(log.Logger, func(string) string, bool) (gradleconfig.TemplateInventory, error) { + return gradleconfig.TemplateInventory{}, inventoryCreationError + }, + func( + gradleconfig.TemplateInventory, + string, + ) error { + return nil + }, + gradleconfig.GradlePropertiesUpdater{ + OsProxy: gradleconfig.OsProxy{ + ReadFileIfExists: func(string) (string, bool, error) { + return "", true, nil + }, + WriteFile: func(string, []byte, os.FileMode) error { return nil }, + }, + }, + ) + + // then + require.EqualError(t, err, inventoryCreationError.Error()) + }) + + t.Run("when template writing fails activateForGradleCmdFn throws error", func(t *testing.T) { + mockLogger := prep() + templateWriteError := errors.New("failed to write template") + + // when + err := activateForGradleCmdFn( + mockLogger, + "~/.gradle", + func(string) string { return "" }, + func(log.Logger, func(string) string, bool) (gradleconfig.TemplateInventory, error) { + return gradleconfig.TemplateInventory{}, nil + }, + func( + gradleconfig.TemplateInventory, + string, + ) error { + return templateWriteError + }, + gradleconfig.GradlePropertiesUpdater{ + OsProxy: gradleconfig.OsProxy{ + ReadFileIfExists: func(string) (string, bool, error) { + return "", true, nil + }, + WriteFile: func(string, []byte, os.FileMode) error { return nil }, + }, + }, + ) + + // then + require.EqualError(t, err, templateWriteError.Error()) + }) + + t.Run("when gradle.property update fails activateForGradleCmdFn throws error", func(t *testing.T) { + mockLogger := prep() + gradlePropertiesUpdateError := errors.New("failed to update gradle.properties") + + // when + err := activateForGradleCmdFn( + mockLogger, + "~/.gradle", + func(string) string { return "" }, + func(log.Logger, func(string) string, bool) (gradleconfig.TemplateInventory, error) { + return gradleconfig.TemplateInventory{}, nil + }, + func( + gradleconfig.TemplateInventory, + string, + ) error { + return nil + }, + gradleconfig.GradlePropertiesUpdater{ + OsProxy: gradleconfig.OsProxy{ + ReadFileIfExists: func(string) (string, bool, error) { + return "", true, nil + }, + WriteFile: func(string, []byte, os.FileMode) error { return gradlePropertiesUpdateError }, + }, + }, + ) + + // then + require.EqualError( + t, + err, + fmt.Errorf( + errFmtFailedToUpdateProps, + fmt.Errorf( + gradleconfig.ErrFmtGradlePropertyWrite, + "~/.gradle/gradle.properties", + gradlePropertiesUpdateError, + ), + ).Error(), + ) + }) +} diff --git a/cmd/asset/verification-metadata.xml b/cmd/asset/verification-metadata.xml index f3294b0a..d4218be1 100644 --- a/cmd/asset/verification-metadata.xml +++ b/cmd/asset/verification-metadata.xml @@ -47,11 +47,6 @@ - - - - - @@ -60,11 +55,6 @@ - - - - - @@ -78,6 +68,11 @@ + + + + + @@ -91,6 +86,11 @@ + + + + + @@ -133,6 +133,14 @@ + + + + + + + + @@ -141,6 +149,14 @@ + + + + + + + + @@ -196,6 +212,14 @@ + + + + + + + + @@ -220,6 +244,14 @@ + + + + + + + + @@ -236,6 +268,14 @@ + + + + + + + + @@ -260,6 +300,14 @@ + + + + + + + + @@ -325,6 +373,11 @@ + + + + + @@ -341,11 +394,6 @@ - - - - - @@ -354,6 +402,11 @@ + + + + + @@ -367,6 +420,11 @@ + + + + + @@ -395,11 +453,6 @@ - - - - - @@ -541,11 +594,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -572,6 +664,19 @@ + + + + + + + + + + + + + @@ -642,6 +747,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cmd/client.go b/cmd/client.go index 11bb308d..a589f7d8 100644 --- a/cmd/client.go +++ b/cmd/client.go @@ -47,7 +47,7 @@ func createKVClient(ctx context.Context, ClientName: params.ClientName, AuthConfig: params.AuthConfig, Logger: params.Logger, - CacheConfigMetadata: common.NewCacheConfigMetadata(params.EnvProvider, params.CommandFunc, params.Logger), + CacheConfigMetadata: common.NewMetadata(params.EnvProvider, params.CommandFunc, params.Logger), CacheOperationID: params.CacheOperationID, }) if err != nil { diff --git a/cmd/enableForBazel.go b/cmd/enableForBazel.go index 0afaf959..8b6ef7e4 100644 --- a/cmd/enableForBazel.go +++ b/cmd/enableForBazel.go @@ -81,8 +81,8 @@ func enableForBazelCmdFn(logger log.Logger, homeDirPath string, envProvider func logger.Infof("(i) RBE is not available at this location") } } - // Metadata - cacheConfig := common.NewCacheConfigMetadata(os.Getenv, + // CacheConfigMetadata + cacheConfig := common.NewMetadata(os.Getenv, func(name string, v ...string) (string, error) { output, err := exec.Command(name, v...).Output() diff --git a/cmd/enable_for_gradle.go b/cmd/enable_for_gradle.go index 3c62d6ba..3cf5cfb0 100644 --- a/cmd/enable_for_gradle.go +++ b/cmd/enable_for_gradle.go @@ -2,23 +2,23 @@ package cmd import ( "context" - "errors" "fmt" "os" "os/exec" - "path/filepath" "github.com/bitrise-io/bitrise-build-cache-cli/internal/config/common" gradleconfig "github.com/bitrise-io/bitrise-build-cache-cli/internal/config/gradle" "github.com/bitrise-io/bitrise-build-cache-cli/internal/gradle" - "github.com/bitrise-io/bitrise-build-cache-cli/internal/stringmerge" "github.com/bitrise-io/go-utils/v2/log" "github.com/bitrise-io/go-utils/v2/pathutil" "github.com/google/uuid" "github.com/spf13/cobra" ) -const gradleHomeNonExpanded = "~/.gradle" +const ( + gradleHomeNonExpanded = "~/.gradle" + FmtErrorEnableForGradle = "adding Gradle plugins failed: %w" +) //nolint:gochecknoglobals var ( @@ -28,8 +28,6 @@ var ( paramRemoteCacheEndpoint string ) -var errInvalidCacheLevel = errors.New("invalid cache validation level, valid options: none, warning, error") - // enableForGradleCmd represents the gradle command var enableForGradleCmd = &cobra.Command{ //nolint:gochecknoglobals Use: "gradle", @@ -79,99 +77,30 @@ func init() { enableForGradleCmd.Flags().StringVar(¶mRemoteCacheEndpoint, "remote-cache-endpoint", "", "Remote cache endpoint URL") } -func writeGradleInit(logger log.Logger, gradleHomePath string, endpointURL string, authToken string, cacheConfigMetadata common.CacheConfigMetadata, prefs gradleconfig.Preferences) error { - logger.Infof("(i) Ensure ~/.gradle and ~/.gradle/init.d directories exist") - gradleInitDPath := filepath.Join(gradleHomePath, "init.d") - err := os.MkdirAll(gradleInitDPath, 0755) //nolint:gomnd,mnd - if err != nil { - return fmt.Errorf("ensure ~/.gradle/init.d exists: %w", err) - } - - logger.Infof("(i) Generate ~/.gradle/init.d/bitrise-build-cache.init.gradle.kts") - initGradleContent, err := gradleconfig.GenerateInitGradle(endpointURL, authToken, prefs, cacheConfigMetadata) - if err != nil { - return fmt.Errorf("generate bitrise-build-cache.init.gradle.kts: %w", err) - } - - logger.Infof("(i) Write ~/.gradle/init.d/bitrise-build-cache.init.gradle.kts") - { - initGradlePath := filepath.Join(gradleInitDPath, "bitrise-build-cache.init.gradle.kts") - err = os.WriteFile(initGradlePath, []byte(initGradleContent), 0755) //nolint:gosec,gomnd,mnd - if err != nil { - return fmt.Errorf("write bitrise-build-cache.init.gradle.kts to %s, error: %w", initGradlePath, err) - } - } - - return nil -} - func enableForGradleCmdFn(logger log.Logger, gradleHomePath string, envProvider func(string) string) error { - logger.Infof("(i) Checking parameters") - - // Required configs - logger.Infof("(i) Check Auth Config") - authConfig, err := common.ReadAuthConfigFromEnvironments(envProvider) + activateForGradleParams.Cache.Enabled = true + activateForGradleParams.Cache.PushEnabled = paramIsPushEnabled + activateForGradleParams.Cache.ValidationLevel = paramValidationLevel + activateForGradleParams.Cache.Endpoint = paramRemoteCacheEndpoint + activateForGradleParams.Analytics.Enabled = paramIsGradleMetricsEnabled + activateForGradleParams.TestDistro.Enabled = false + + templateInventory, err := activateForGradleParams.TemplateInventory(logger, envProvider, isDebugLogMode) if err != nil { - return fmt.Errorf("read auth config from environment variables: %w", err) - } - authToken := authConfig.TokenInGradleFormat() - - // Optional configs - // EndpointURL - endpointURL := common.SelectCacheEndpointURL(paramRemoteCacheEndpoint, envProvider) - logger.Infof("(i) Build Cache Endpoint URL: %s", endpointURL) - logger.Infof("(i) Push new cache entries: %t", paramIsPushEnabled) - logger.Infof("(i) Cache entry validation level: %s", paramValidationLevel) - logger.Infof("(i) Collect metrics for cache insights: %t", paramIsGradleMetricsEnabled) - logger.Infof("(i) Debug mode and verbose logs: %t", isDebugLogMode) - - if paramValidationLevel != string(gradleconfig.CacheValidationLevelNone) && - paramValidationLevel != string(gradleconfig.CacheValidationLevelWarning) && - paramValidationLevel != string(gradleconfig.CacheValidationLevelError) { - logger.Errorf("Invalid validation level: '%s'", paramValidationLevel) - - return errInvalidCacheLevel - } - // Metadata - cacheConfigMetadata := common.NewCacheConfigMetadata(os.Getenv, - func(name string, v ...string) (string, error) { - output, err := exec.Command(name, v...).Output() - - return string(output), err - }, logger) - logger.Infof("(i) Cache Config Metadata: %+v", cacheConfigMetadata) - - prefs := gradleconfig.Preferences{ - IsDependencyOnly: false, - IsPushEnabled: paramIsPushEnabled, - CacheLevelValidation: gradleconfig.CacheValidationLevel(paramValidationLevel), - IsAnalyticsEnabled: paramIsGradleMetricsEnabled, - IsDebugEnabled: isDebugLogMode, + return fmt.Errorf(FmtErrorEnableForGradle, err) } - if err := writeGradleInit(logger, gradleHomePath, endpointURL, authToken, cacheConfigMetadata, prefs); err != nil { - return err - } - - logger.Infof("(i) Write ~/.gradle/gradle.properties") - { - gradlePropertiesPath := filepath.Join(gradleHomePath, "gradle.properties") - currentGradlePropsFileContent, isGradlePropsExists, err := readFileIfExists(gradlePropertiesPath) - if err != nil { - return fmt.Errorf("check if gradle.properties exists at %s, error: %w", gradlePropertiesPath, err) - } - logger.Debugf("isGradlePropsExists: %t", isGradlePropsExists) - gradlePropertiesContent := stringmerge.ChangeContentInBlock( - currentGradlePropsFileContent, - "# [start] generated-by-bitrise-build-cache", - "# [end] generated-by-bitrise-build-cache", - "org.gradle.caching=true", - ) + if err := templateInventory.WriteToGradleInit( + logger, + gradleHomePath, + gradleconfig.DefaultOsProxy(), + gradleconfig.DefaultTemplateProxy(), + ); err != nil { + return fmt.Errorf(FmtErrorEnableForGradle, err) + } - err = os.WriteFile(gradlePropertiesPath, []byte(gradlePropertiesContent), 0755) //nolint:gosec,gomnd,mnd - if err != nil { - return fmt.Errorf("write gradle.properties to %s, error: %w", gradlePropertiesPath, err) - } + if err := gradleconfig.DefaultGradlePropertiesUpdater().UpdateGradleProps(activateForGradleParams, logger, gradleHomePath); err != nil { + return fmt.Errorf(FmtErrorEnableForGradle, err) } return nil @@ -204,10 +133,7 @@ func getPlugins(ctx context.Context, logger log.Logger, envProvider func(string) pluginCacher := gradle.PluginCacher{} - if err = pluginCacher.CachePlugins(ctx, kvClient, logger, []gradle.Plugin{ - gradle.PluginAnalytics(), - gradle.PluginCache(), - }); err != nil { + if err = pluginCacher.CachePlugins(ctx, kvClient, logger, gradle.Plugins()); err != nil { return fmt.Errorf("caching plugins: %w", err) } diff --git a/cmd/enable_for_gradle_test.go b/cmd/enable_for_gradle_test.go index bc47c11b..5b8068c8 100644 --- a/cmd/enable_for_gradle_test.go +++ b/cmd/enable_for_gradle_test.go @@ -1,9 +1,12 @@ package cmd import ( + "fmt" "path/filepath" "testing" + "github.com/bitrise-io/bitrise-build-cache-cli/internal/config/common" + gradleconfig "github.com/bitrise-io/bitrise-build-cache-cli/internal/config/gradle" "github.com/bitrise-io/go-utils/v2/log" "github.com/bitrise-io/go-utils/v2/mocks" "github.com/bitrise-io/go-utils/v2/pathutil" @@ -35,10 +38,10 @@ func Test_enableForGradleCmdFn(t *testing.T) { err := enableForGradleCmdFn(mockLogger, tmpGradleHomeDir, envVars) // then - require.EqualError(t, err, "read auth config from environment variables: BITRISE_BUILD_CACHE_AUTH_TOKEN or BITRISEIO_BITRISE_SERVICES_ACCESS_TOKEN environment variable not set") + require.EqualError(t, err, fmt.Errorf(FmtErrorEnableForGradle, fmt.Errorf(gradleconfig.ErrFmtReadAutConfig, common.ErrAuthTokenNotProvided)).Error()) }) - t.Run("No envs specified", func(t *testing.T) { + t.Run("Envs specified", func(t *testing.T) { mockLogger, tmpGradleHomeDir := prep() envVars := createEnvProvider(map[string]string{ "BITRISE_BUILD_CACHE_AUTH_TOKEN": "AuthTokenValue", diff --git a/cmd/gradleVerificationAddDeps.go b/cmd/gradleVerificationAddDeps.go index 6bcd85bd..50304e0d 100644 --- a/cmd/gradleVerificationAddDeps.go +++ b/cmd/gradleVerificationAddDeps.go @@ -3,9 +3,7 @@ package cmd import ( "fmt" "os" - "os/exec" - "github.com/bitrise-io/bitrise-build-cache-cli/internal/config/common" gradleconfig "github.com/bitrise-io/bitrise-build-cache-cli/internal/config/gradle" "github.com/bitrise-io/go-utils/v2/log" "github.com/bitrise-io/go-utils/v2/pathutil" @@ -15,8 +13,8 @@ import ( // addGradleVerificationReferenceDeps represents the gradle command var addGradleVerificationReferenceDeps = &cobra.Command{ //nolint:gochecknoglobals Use: "add-reference-deps", - Short: "Add Bitrise Build Cache plugins to the project (but do not enable it)", - Long: `Add Bitrise Build Cache plugins to the project (but do not enable it) + Short: "Add Bitrise Build Cache plugins to the project (but do not enable them)", + Long: `Add Bitrise Build Cache plugins to the project (but do not enable them) This command will: - Create a ~/.gradle/init.d/bitrise-build-cache.init.gradle.kts file with the necessary configs. This file will be overwritten. @@ -49,33 +47,31 @@ func init() { } func addGradlePluginsFn(logger log.Logger, gradleHomePath string, envProvider func(string) string) error { - logger.Infof("(i) Checking parameters") + activateForGradleParams.Cache.Enabled = false + activateForGradleParams.Cache.JustDependency = true + activateForGradleParams.Analytics.Enabled = false + activateForGradleParams.Analytics.JustDependency = true + activateForGradleParams.TestDistro.Enabled = false + activateForGradleParams.TestDistro.JustDependency = true - // Optional configs - // EndpointURL - endpointURL := common.SelectCacheEndpointURL(paramRemoteCacheEndpoint, envProvider) - logger.Infof("(i) Build Cache Endpoint URL: %s", endpointURL) - logger.Infof("(i) Debug mode and verbose logs: %t", isDebugLogMode) - - // Metadata - cacheConfigMetadata := common.NewCacheConfigMetadata(os.Getenv, func(name string, v ...string) (string, error) { - output, err := exec.Command(name, v...).Output() - - return string(output), err - }, logger) - logger.Infof("(i) Cache Config Metadata: %+v", cacheConfigMetadata) - - authToken := "placeholder-token" - prefs := gradleconfig.Preferences{ - IsDependencyOnly: true, - IsPushEnabled: false, - CacheLevelValidation: gradleconfig.CacheValidationLevelNone, - IsAnalyticsEnabled: true, - IsDebugEnabled: isDebugLogMode, + templateInventory, err := activateForGradleParams.TemplateInventory(logger, envProvider, isDebugLogMode) + if err != nil { + return fmt.Errorf(FmtErrorGradleVerification, err) } - if err := writeGradleInit(logger, gradleHomePath, endpointURL, authToken, cacheConfigMetadata, prefs); err != nil { - return err + + if err := templateInventory.WriteToGradleInit( + logger, + gradleHomePath, + gradleconfig.DefaultOsProxy(), + gradleconfig.DefaultTemplateProxy(), + ); err != nil { + return fmt.Errorf(FmtErrorGradleVerification, err) } return nil } + +//nolint:gochecknoglobals +var ( + FmtErrorGradleVerification = "adding Gradle plugins failed: %w" +) diff --git a/internal/config/bazel/bazel_config.go b/internal/config/bazel/bazel_config.go index f9fd66d2..332b6894 100644 --- a/internal/config/bazel/bazel_config.go +++ b/internal/config/bazel/bazel_config.go @@ -24,7 +24,7 @@ type templateInventory struct { WorkspaceID string AuthToken string IsTimestampsEnabled bool - // Metadata + // CacheConfigMetadata CacheConfigMetadata common.CacheConfigMetadata } diff --git a/internal/config/common/auth.go b/internal/config/common/auth.go index 10577682..725acef4 100644 --- a/internal/config/common/auth.go +++ b/internal/config/common/auth.go @@ -3,8 +3,8 @@ package common import "errors" var ( - errAuthTokenNotProvided = errors.New("BITRISE_BUILD_CACHE_AUTH_TOKEN or BITRISEIO_BITRISE_SERVICES_ACCESS_TOKEN environment variable not set") - errWorkspaceIDNotProvided = errors.New("BITRISE_BUILD_CACHE_WORKSPACE_ID environment variable not set") + ErrAuthTokenNotProvided = errors.New("BITRISE_BUILD_CACHE_AUTH_TOKEN or BITRISEIO_BITRISE_SERVICES_ACCESS_TOKEN environment variable not set") + ErrWorkspaceIDNotProvided = errors.New("BITRISE_BUILD_CACHE_WORKSPACE_ID environment variable not set") ) // CacheAuthConfig holds the auth config for the cache. @@ -44,8 +44,8 @@ func ReadAuthConfigFromEnvironments(envProvider func(string) string) (CacheAuthC // Write specific errors for each case. if len(authTokenEnv) < 1 { - return CacheAuthConfig{}, errAuthTokenNotProvided + return CacheAuthConfig{}, ErrAuthTokenNotProvided } - return CacheAuthConfig{}, errWorkspaceIDNotProvided + return CacheAuthConfig{}, ErrWorkspaceIDNotProvided } diff --git a/internal/config/common/auth_test.go b/internal/config/common/auth_test.go index a1badcc4..c89844f9 100644 --- a/internal/config/common/auth_test.go +++ b/internal/config/common/auth_test.go @@ -16,7 +16,7 @@ func TestReadAuthConfigFromEnvironments(t *testing.T) { { name: "No envs specified", envVars: map[string]string{}, - expectedError: errAuthTokenNotProvided, + expectedError: ErrAuthTokenNotProvided, }, { name: "Only BITRISEIO_BITRISE_SERVICES_ACCESS_TOKEN set", @@ -45,14 +45,14 @@ func TestReadAuthConfigFromEnvironments(t *testing.T) { envVars: map[string]string{ "BITRISE_BUILD_CACHE_AUTH_TOKEN": "auth-token", }, - expectedError: errWorkspaceIDNotProvided, + expectedError: ErrWorkspaceIDNotProvided, }, { name: "Only BITRISE_BUILD_CACHE_WORKSPACE_ID set", envVars: map[string]string{ "BITRISE_BUILD_CACHE_WORKSPACE_ID": "workspace-id", }, - expectedError: errAuthTokenNotProvided, + expectedError: ErrAuthTokenNotProvided, }, } diff --git a/internal/config/common/cache_config.go b/internal/config/common/cache_config.go index 66a47868..e72ff05d 100644 --- a/internal/config/common/cache_config.go +++ b/internal/config/common/cache_config.go @@ -90,8 +90,8 @@ func createCacheConfigMetadata(provider, repoURL string, } } -// NewCacheConfigMetadata creates a new CacheConfigMetadata instance based on the environment variables. -func NewCacheConfigMetadata(envProvider EnvProviderFunc, commandFunc CommandFunc, logger log.Logger) CacheConfigMetadata { +// NewMetadata creates a new CacheConfigMetadata instance based on the environment variables. +func NewMetadata(envProvider EnvProviderFunc, commandFunc CommandFunc, logger log.Logger) CacheConfigMetadata { hostMetadata := generateHostMetadata(envProvider, commandFunc, logger) provider := detectCIProvider(envProvider) diff --git a/internal/config/common/cache_config_test.go b/internal/config/common/cache_config_test.go index 41a7315b..0548719e 100644 --- a/internal/config/common/cache_config_test.go +++ b/internal/config/common/cache_config_test.go @@ -200,10 +200,10 @@ func TestNewCacheConfigMetadata(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := NewCacheConfigMetadata(tt.args.envProvider, + if got := NewMetadata(tt.args.envProvider, tt.args.commandFunc, log.NewLogger()); !reflect.DeepEqual(got, tt.want) { - t.Errorf("NewCacheConfigMetadata() = %v, want %v", got, tt.want) + t.Errorf("NewMetadata() = %v, want %v", got, tt.want) } }) } diff --git a/internal/config/gradle/activate_for_gradle_params.go b/internal/config/gradle/activate_for_gradle_params.go new file mode 100644 index 00000000..d1b488f2 --- /dev/null +++ b/internal/config/gradle/activate_for_gradle_params.go @@ -0,0 +1,248 @@ +package gradleconfig + +import ( + "errors" + "fmt" + "os/exec" + + "github.com/bitrise-io/bitrise-build-cache-cli/internal/config/common" + "github.com/bitrise-io/bitrise-build-cache-cli/internal/consts" + "github.com/bitrise-io/go-utils/v2/log" +) + +const ( + errFmtInvalidCacheLevel = "invalid cache validation level, valid options: none, warning, error" + errFmtTestDistroAppSlug = "test distribution plugin was enabled but no BITRISE_APP_SLUG was specified" + ErrFmtReadAutConfig = "read auth config from environment variables: %w" + errFmtCacheConfigCreation = "couldn't create cache configuration: %w" + errFmtTestDistroConfigCreation = "couldn't create test distribution configuration: %w" + errFmtInvalidValidationLevel = "invalid validation level: '%s'" +) + +type CacheParams struct { + Enabled bool + JustDependency bool + PushEnabled bool + ValidationLevel string + Endpoint string +} + +type AnalyticsParams struct { + Enabled bool + JustDependency bool +} + +type TestDistroParams struct { + Enabled bool + JustDependency bool +} + +type ActivateForGradleParams struct { + Cache CacheParams + Analytics AnalyticsParams + TestDistro TestDistroParams +} + +func DefaultActivateForGradleParams() ActivateForGradleParams { + return ActivateForGradleParams{ + Cache: CacheParams{ + Enabled: false, + JustDependency: false, + PushEnabled: false, + ValidationLevel: string(CacheValidationLevelWarning), + }, + Analytics: AnalyticsParams{ + Enabled: true, + JustDependency: false, + }, + TestDistro: TestDistroParams{ + Enabled: false, + JustDependency: false, + }, + } +} + +func (params ActivateForGradleParams) TemplateInventory( + logger log.Logger, + envProvider func(string) string, + isDebug bool, +) (TemplateInventory, error) { + logger.Infof("(i) Checking parameters") + + commonInventory, err := params.commonTemplateInventory(logger, envProvider, isDebug) + if err != nil { + return TemplateInventory{}, err + } + + cacheInventory, err := params.cacheTemplateInventory(logger, envProvider) + if err != nil { + return TemplateInventory{}, fmt.Errorf(errFmtCacheConfigCreation, err) + } + + analyticsInventory := params.analyticsTemplateInventory(logger) + + testDistroInventory, err := params.testDistroTemplateInventory(logger, envProvider, isDebug) + if err != nil { + return TemplateInventory{}, fmt.Errorf(errFmtTestDistroConfigCreation, err) + } + + return TemplateInventory{ + Common: commonInventory, + Cache: cacheInventory, + Analytics: analyticsInventory, + TestDistro: testDistroInventory, + }, nil +} + +func (params ActivateForGradleParams) commonTemplateInventory( + logger log.Logger, + envProvider func(string) string, + isDebug bool, +) (PluginCommonTemplateInventory, error) { + logger.Infof("(i) Debug mode and verbose logs: %t", isDebug) + + // Required configs + logger.Infof("(i) Check Auth Config") + authConfig, err := common.ReadAuthConfigFromEnvironments(envProvider) + if err != nil { + return PluginCommonTemplateInventory{}, + fmt.Errorf(ErrFmtReadAutConfig, err) + } + authToken := authConfig.TokenInGradleFormat() + + cacheConfig := common.NewMetadata(envProvider, + func(name string, v ...string) (string, error) { + output, err := exec.Command(name, v...).Output() + + return string(output), err + }, + logger) + logger.Infof("(i) Cache Config: %+v", cacheConfig) + + return PluginCommonTemplateInventory{ + AuthToken: authToken, + Debug: isDebug, + AppSlug: cacheConfig.BitriseAppID, + CIProvider: cacheConfig.CIProvider, + }, nil +} + +func (params ActivateForGradleParams) cacheTemplateInventory( + logger log.Logger, + envProvider func(string) string, +) (CacheTemplateInventory, error) { + if !params.Cache.JustDependency && !params.Cache.Enabled { + logger.Infof("(i) Cache plugin usage: %+v", UsageLevelNone) + + return CacheTemplateInventory{ + Usage: UsageLevelNone, + }, nil + } + + if params.Cache.JustDependency && !params.Cache.Enabled { + logger.Infof("(i) Cache plugin usage: %+v", UsageLevelDependency) + + return CacheTemplateInventory{ + Usage: UsageLevelDependency, + Version: consts.GradleRemoteBuildCachePluginDepVersion, + }, nil + } + + logger.Infof("(i) Cache plugin usage: %+v", UsageLevelEnabled) + + cacheEndpointURL := common.SelectCacheEndpointURL(params.Cache.Endpoint, envProvider) + logger.Infof("(i) Build Cache Endpoint URL: %s", cacheEndpointURL) + logger.Infof("(i) Push new cache entries: %t", params.Cache.PushEnabled) + logger.Infof("(i) Cache entry validation level: %s", params.Cache.ValidationLevel) + + if params.Cache.ValidationLevel != string(CacheValidationLevelNone) && + params.Cache.ValidationLevel != string(CacheValidationLevelWarning) && + params.Cache.ValidationLevel != string(CacheValidationLevelError) { + logger.Errorf(errFmtInvalidValidationLevel, params.Cache.ValidationLevel) + + return CacheTemplateInventory{}, errors.New(errFmtInvalidCacheLevel) + } + + return CacheTemplateInventory{ + Usage: UsageLevelEnabled, + Version: consts.GradleRemoteBuildCachePluginDepVersion, + EndpointURLWithPort: cacheEndpointURL, + IsPushEnabled: params.Cache.PushEnabled, + ValidationLevel: params.Cache.ValidationLevel, + }, nil +} + +func (params ActivateForGradleParams) analyticsTemplateInventory( + logger log.Logger, +) AnalyticsTemplateInventory { + if !params.Analytics.JustDependency && !params.Analytics.Enabled { + logger.Infof("(i) Analytics plugin usage: %+v", UsageLevelNone) + + return AnalyticsTemplateInventory{ + Usage: UsageLevelNone, + } + } + + if params.Analytics.JustDependency && !params.Analytics.Enabled { + logger.Infof("(i) Analytics plugin usage: %+v", UsageLevelDependency) + + return AnalyticsTemplateInventory{ + Usage: UsageLevelDependency, + Version: consts.GradleAnalyticsPluginDepVersion, + } + } + + logger.Infof("(i) Analytics plugin usage: %+v", UsageLevelEnabled) + + return AnalyticsTemplateInventory{ + Usage: UsageLevelEnabled, + Version: consts.GradleAnalyticsPluginDepVersion, + Endpoint: consts.GradleAnalyticsEndpoint, + Port: consts.GradleAnalyticsPort, + HTTPEndpoint: consts.GradleAnalyticsHTTPEndpoint, + } +} + +func (params ActivateForGradleParams) testDistroTemplateInventory( + logger log.Logger, + envProvider func(string) string, + isDebug bool, +) (TestDistroTemplateInventory, error) { + if !params.TestDistro.JustDependency && !params.TestDistro.Enabled { + logger.Infof("(i) Test distribution plugin usage: %+v", UsageLevelNone) + + return TestDistroTemplateInventory{ + Usage: UsageLevelNone, + }, nil + } + + if params.TestDistro.JustDependency && !params.TestDistro.Enabled { + logger.Infof("(i) Test distribution plugin usage: %+v", UsageLevelDependency) + + return TestDistroTemplateInventory{ + Usage: UsageLevelDependency, + Version: consts.GradleTestDistributionPluginDepVersion, + }, nil + } + + logger.Infof("(i) Test distribution plugin usage: %+v", UsageLevelEnabled) + + appSlug := envProvider("BITRISE_APP_SLUG") + if len(appSlug) < 1 { + return TestDistroTemplateInventory{}, errors.New(errFmtTestDistroAppSlug) + } + + logLevel := "warning" + if isDebug { + logLevel = "debug" + } + + return TestDistroTemplateInventory{ + Usage: UsageLevelEnabled, + Version: consts.GradleTestDistributionPluginDepVersion, + Endpoint: consts.GradleTestDistributionEndpoint, + KvEndpoint: consts.GradleTestDistributionKvEndpoint, + Port: consts.GradleTestDistributionPort, + LogLevel: logLevel, + }, nil +} diff --git a/internal/config/gradle/activate_for_gradle_params_test.go b/internal/config/gradle/activate_for_gradle_params_test.go new file mode 100644 index 00000000..7e3da02f --- /dev/null +++ b/internal/config/gradle/activate_for_gradle_params_test.go @@ -0,0 +1,345 @@ +//nolint:maintidx +package gradleconfig + +import ( + "errors" + "fmt" + "testing" + + "github.com/bitrise-io/bitrise-build-cache-cli/internal/config/common" + "github.com/bitrise-io/bitrise-build-cache-cli/internal/consts" + "github.com/bitrise-io/go-utils/v2/log" + "github.com/bitrise-io/go-utils/v2/mocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func Test_activateForGradleParams(t *testing.T) { + prep := func() log.Logger { + mockLogger := &mocks.Logger{} + mockLogger.On("Infof", mock.Anything).Return() + mockLogger.On("Infof", mock.Anything, mock.Anything).Return() + mockLogger.On("Debugf", mock.Anything).Return() + mockLogger.On("Debugf", mock.Anything, mock.Anything).Return() + mockLogger.On("Errorf", mock.Anything).Return() + mockLogger.On("Errorf", mock.Anything, mock.Anything).Return() + + return mockLogger + } + + tests := []struct { + name string + debug bool + params ActivateForGradleParams + envVars map[string]string + want TemplateInventory + wantErr string + }{ + { + name: "no auth token", + params: ActivateForGradleParams{ + Cache: CacheParams{Enabled: false}, + Analytics: AnalyticsParams{Enabled: false}, + TestDistro: TestDistroParams{Enabled: false}, + }, + envVars: map[string]string{}, + wantErr: fmt.Errorf(ErrFmtReadAutConfig, common.ErrAuthTokenNotProvided).Error(), + }, + { + name: "no workspaceID", + params: ActivateForGradleParams{ + Cache: CacheParams{Enabled: false}, + Analytics: AnalyticsParams{Enabled: false}, + TestDistro: TestDistroParams{Enabled: false}, + }, + envVars: map[string]string{ + "BITRISE_BUILD_CACHE_AUTH_TOKEN": "AuthTokenValue", + }, + wantErr: fmt.Errorf(ErrFmtReadAutConfig, common.ErrWorkspaceIDNotProvided).Error(), + }, + { + name: "no plugins", + params: ActivateForGradleParams{ + Cache: CacheParams{Enabled: false}, + Analytics: AnalyticsParams{Enabled: false}, + TestDistro: TestDistroParams{Enabled: false}, + }, + envVars: map[string]string{ + "BITRISE_BUILD_CACHE_AUTH_TOKEN": "AuthTokenValue", + "BITRISE_BUILD_CACHE_WORKSPACE_ID": "WorkspaceIDValue", + }, + want: TemplateInventory{ + Common: PluginCommonTemplateInventory{ + AuthToken: "WorkspaceIDValue:AuthTokenValue", + }, + Cache: CacheTemplateInventory{ + Usage: UsageLevelNone, + }, + Analytics: AnalyticsTemplateInventory{ + Usage: UsageLevelNone, + }, + TestDistro: TestDistroTemplateInventory{ + Usage: UsageLevelNone, + }, + }, + }, + { + name: "dependency only plugins", + params: ActivateForGradleParams{ + Cache: CacheParams{ + Enabled: false, + JustDependency: true, + }, + Analytics: AnalyticsParams{ + Enabled: false, + JustDependency: true, + }, + TestDistro: TestDistroParams{ + Enabled: false, + JustDependency: true, + }, + }, + envVars: map[string]string{ + "BITRISE_BUILD_CACHE_AUTH_TOKEN": "AuthTokenValue", + "BITRISE_BUILD_CACHE_WORKSPACE_ID": "WorkspaceIDValue", + }, + want: TemplateInventory{ + Common: PluginCommonTemplateInventory{ + AuthToken: "WorkspaceIDValue:AuthTokenValue", + }, + Cache: CacheTemplateInventory{ + Usage: UsageLevelDependency, + Version: consts.GradleRemoteBuildCachePluginDepVersion, + }, + Analytics: AnalyticsTemplateInventory{ + Usage: UsageLevelDependency, + Version: consts.GradleAnalyticsPluginDepVersion, + }, + TestDistro: TestDistroTemplateInventory{ + Usage: UsageLevelDependency, + Version: consts.GradleTestDistributionPluginDepVersion, + }, + }, + }, + { + name: "activate cache", + params: ActivateForGradleParams{ + Cache: CacheParams{ + Enabled: true, + JustDependency: true, // gets overridden by enable + ValidationLevel: string(CacheValidationLevelError), + Endpoint: "EndpointValue", + PushEnabled: true, + }, + Analytics: AnalyticsParams{ + Enabled: false, + }, + TestDistro: TestDistroParams{ + Enabled: false, + }, + }, + envVars: map[string]string{ + "BITRISE_BUILD_CACHE_AUTH_TOKEN": "AuthTokenValue", + "BITRISE_BUILD_CACHE_WORKSPACE_ID": "WorkspaceIDValue", + }, + want: TemplateInventory{ + Common: PluginCommonTemplateInventory{ + AuthToken: "WorkspaceIDValue:AuthTokenValue", + }, + Cache: CacheTemplateInventory{ + Usage: UsageLevelEnabled, + Version: consts.GradleRemoteBuildCachePluginDepVersion, + EndpointURLWithPort: "EndpointValue", + IsPushEnabled: true, + ValidationLevel: string(CacheValidationLevelError), + }, + Analytics: AnalyticsTemplateInventory{ + Usage: UsageLevelNone, + }, + TestDistro: TestDistroTemplateInventory{ + Usage: UsageLevelNone, + }, + }, + }, + { + name: "given invalid cache validation level cache activation throws error", + params: ActivateForGradleParams{ + Cache: CacheParams{ + Enabled: true, + ValidationLevel: "InvalidLevel", + Endpoint: "EndpointValue", + PushEnabled: true, + }, + Analytics: AnalyticsParams{ + Enabled: false, + }, + TestDistro: TestDistroParams{ + Enabled: false, + }, + }, + envVars: map[string]string{ + "BITRISE_BUILD_CACHE_AUTH_TOKEN": "AuthTokenValue", + "BITRISE_BUILD_CACHE_WORKSPACE_ID": "WorkspaceIDValue", + }, + wantErr: fmt.Errorf(errFmtCacheConfigCreation, errors.New(errFmtInvalidCacheLevel)).Error(), + }, + { + name: "activate analytics", + params: ActivateForGradleParams{ + Cache: CacheParams{ + Enabled: false, + }, + Analytics: AnalyticsParams{ + Enabled: true, + JustDependency: true, // gets overridden by enable + }, + TestDistro: TestDistroParams{ + Enabled: false, + }, + }, + envVars: map[string]string{ + "BITRISE_BUILD_CACHE_AUTH_TOKEN": "AuthTokenValue", + "BITRISE_BUILD_CACHE_WORKSPACE_ID": "WorkspaceIDValue", + }, + want: TemplateInventory{ + Common: PluginCommonTemplateInventory{ + AuthToken: "WorkspaceIDValue:AuthTokenValue", + }, + Cache: CacheTemplateInventory{ + Usage: UsageLevelNone, + }, + Analytics: AnalyticsTemplateInventory{ + Usage: UsageLevelEnabled, + Version: consts.GradleAnalyticsPluginDepVersion, + Endpoint: consts.GradleAnalyticsEndpoint, + Port: consts.GradleAnalyticsPort, + HTTPEndpoint: consts.GradleAnalyticsHTTPEndpoint, + }, + TestDistro: TestDistroTemplateInventory{ + Usage: UsageLevelNone, + }, + }, + }, + { + name: "activate test distro", + params: ActivateForGradleParams{ + Cache: CacheParams{ + Enabled: false, + }, + Analytics: AnalyticsParams{ + Enabled: false, + }, + TestDistro: TestDistroParams{ + Enabled: true, + JustDependency: true, // gets overridden by enable + }, + }, + envVars: map[string]string{ + "BITRISE_BUILD_CACHE_AUTH_TOKEN": "AuthTokenValue", + "BITRISE_BUILD_CACHE_WORKSPACE_ID": "WorkspaceIDValue", + "BITRISE_IO": "true", + "BITRISE_APP_SLUG": "AppSlugValue", + }, + want: TemplateInventory{ + Common: PluginCommonTemplateInventory{ + AuthToken: "WorkspaceIDValue:AuthTokenValue", + AppSlug: "AppSlugValue", + CIProvider: "bitrise", + }, + Cache: CacheTemplateInventory{ + Usage: UsageLevelNone, + }, + Analytics: AnalyticsTemplateInventory{ + Usage: UsageLevelNone, + }, + TestDistro: TestDistroTemplateInventory{ + Usage: UsageLevelEnabled, + Version: consts.GradleTestDistributionPluginDepVersion, + Endpoint: consts.GradleTestDistributionEndpoint, + KvEndpoint: consts.GradleTestDistributionKvEndpoint, + Port: consts.GradleTestDistributionPort, + LogLevel: "warning", + }, + }, + }, + { + name: "activating test distro while missing app slug throws error", + params: ActivateForGradleParams{ + Cache: CacheParams{ + Enabled: false, + }, + Analytics: AnalyticsParams{ + Enabled: false, + }, + TestDistro: TestDistroParams{ + Enabled: true, + JustDependency: true, // gets overridden by enable + }, + }, + envVars: map[string]string{ + "BITRISE_BUILD_CACHE_AUTH_TOKEN": "AuthTokenValue", + "BITRISE_BUILD_CACHE_WORKSPACE_ID": "WorkspaceIDValue", + "BITRISE_IO": "true", + }, + wantErr: fmt.Errorf(errFmtTestDistroConfigCreation, errors.New(errFmtTestDistroAppSlug)).Error(), + }, + { + name: "activate plugins with debug mode", + debug: true, + params: ActivateForGradleParams{ + Cache: CacheParams{ + Enabled: false, + }, + Analytics: AnalyticsParams{ + Enabled: false, + }, + TestDistro: TestDistroParams{ + Enabled: true, + JustDependency: true, // gets overridden by enable + }, + }, + envVars: map[string]string{ + "BITRISE_BUILD_CACHE_AUTH_TOKEN": "AuthTokenValue", + "BITRISE_BUILD_CACHE_WORKSPACE_ID": "WorkspaceIDValue", + "BITRISE_IO": "true", + "BITRISE_APP_SLUG": "AppSlugValue", + }, + want: TemplateInventory{ + Common: PluginCommonTemplateInventory{ + AuthToken: "WorkspaceIDValue:AuthTokenValue", + Debug: true, + AppSlug: "AppSlugValue", + CIProvider: "bitrise", + }, + Cache: CacheTemplateInventory{ + Usage: UsageLevelNone, + }, + Analytics: AnalyticsTemplateInventory{ + Usage: UsageLevelNone, + }, + TestDistro: TestDistroTemplateInventory{ + Usage: UsageLevelEnabled, + Version: consts.GradleTestDistributionPluginDepVersion, + Endpoint: consts.GradleTestDistributionEndpoint, + KvEndpoint: consts.GradleTestDistributionKvEndpoint, + Port: consts.GradleTestDistributionPort, + LogLevel: "debug", + }, + }, + }, + } + for _, tt := range tests { //nolint:varnamelen + t.Run(tt.name, func(t *testing.T) { + mockLogger := prep() + envProvider := func(key string) string { return tt.envVars[key] } + got, err := tt.params.TemplateInventory(mockLogger, envProvider, tt.debug) + if tt.wantErr != "" { + require.EqualError(t, err, tt.wantErr) + } else { + require.NoError(t, err) + } + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/config/gradle/cache_validation_level.go b/internal/config/gradle/cache_validation_level.go new file mode 100644 index 00000000..8203475f --- /dev/null +++ b/internal/config/gradle/cache_validation_level.go @@ -0,0 +1,10 @@ +package gradleconfig + +type CacheValidationLevel string + +//nolint:gochecknoglobals +var ( + CacheValidationLevelNone CacheValidationLevel = "none" + CacheValidationLevelWarning CacheValidationLevel = "warning" + CacheValidationLevelError CacheValidationLevel = "error" +) diff --git a/internal/config/gradle/gradle_init_template_inventory.go b/internal/config/gradle/gradle_init_template_inventory.go new file mode 100644 index 00000000..5a4cb4f7 --- /dev/null +++ b/internal/config/gradle/gradle_init_template_inventory.go @@ -0,0 +1,63 @@ +package gradleconfig + +type UsageLevel string + +//nolint:gochecknoglobals +var ( + UsageLevelNone UsageLevel = "none" + UsageLevelDependency UsageLevel = "dependency" + UsageLevelEnabled UsageLevel = "enabled" +) + +type CacheTemplateInventory struct { + Usage UsageLevel + Version string + EndpointURLWithPort string + IsPushEnabled bool + ValidationLevel string +} + +type AnalyticsTemplateInventory struct { + Usage UsageLevel + Version string + Endpoint string + Port int + HTTPEndpoint string +} + +type TestDistroTemplateInventory struct { + Usage UsageLevel + Version string + Endpoint string + KvEndpoint string + Port int + LogLevel string +} + +type PluginCommonTemplateInventory struct { + AuthToken string + Debug bool + AppSlug string + CIProvider string +} + +type TemplateInventory struct { + Common PluginCommonTemplateInventory + Cache CacheTemplateInventory + Analytics AnalyticsTemplateInventory + TestDistro TestDistroTemplateInventory +} + +func (inventory TemplateInventory) HasDependencies() bool { + if inventory.Analytics.Usage == UsageLevelDependency || inventory.Analytics.Usage == UsageLevelEnabled { + return true + } + if inventory.Cache.Usage == UsageLevelDependency || inventory.Cache.Usage == UsageLevelEnabled { + return true + } + if inventory.TestDistro.Usage == UsageLevelDependency || inventory.TestDistro.Usage == UsageLevelEnabled { + return true + } + + return false +} diff --git a/internal/config/gradle/gradle_properties_from_params.go b/internal/config/gradle/gradle_properties_from_params.go new file mode 100644 index 00000000..d29093b9 --- /dev/null +++ b/internal/config/gradle/gradle_properties_from_params.go @@ -0,0 +1,58 @@ +package gradleconfig + +import ( + "fmt" + "path/filepath" + + "github.com/bitrise-io/bitrise-build-cache-cli/internal/stringmerge" + "github.com/bitrise-io/go-utils/v2/log" +) + +const ( + ErrFmtGradlePropertiesCheck = "check if gradle.properties exists at %s, error: %w" + ErrFmtGradlePropertyWrite = "write gradle.properties to %s, error: %w" +) + +type GradlePropertiesUpdater struct { + OsProxy OsProxy +} + +func DefaultGradlePropertiesUpdater() GradlePropertiesUpdater { + return GradlePropertiesUpdater{ + OsProxy: DefaultOsProxy(), + } +} + +func (updater GradlePropertiesUpdater) UpdateGradleProps( + params ActivateForGradleParams, + logger log.Logger, + gradleHomePath string, +) error { + logger.Infof("(i) Write ~/.gradle/gradle.properties") + + gradlePropertiesPath := filepath.Join(gradleHomePath, "gradle.properties") + currentGradlePropsFileContent, isGradlePropsExists, err := updater.OsProxy.ReadFileIfExists(gradlePropertiesPath) + if err != nil { + return fmt.Errorf(ErrFmtGradlePropertiesCheck, gradlePropertiesPath, err) + } + logger.Debugf("isGradlePropsExists: %t", isGradlePropsExists) + + cachingLine := "org.gradle.caching=true" + if !params.Cache.Enabled { + cachingLine = "org.gradle.caching=false" + } + + gradlePropertiesContent := stringmerge.ChangeContentInBlock( + currentGradlePropsFileContent, + "# [start] generated-by-bitrise-build-cache", + "# [end] generated-by-bitrise-build-cache", + cachingLine, + ) + + err = updater.OsProxy.WriteFile(gradlePropertiesPath, []byte(gradlePropertiesContent), 0755) //nolint:gosec,gomnd,mnd + if err != nil { + return fmt.Errorf(ErrFmtGradlePropertyWrite, gradlePropertiesPath, err) + } + + return nil +} diff --git a/internal/config/gradle/gradle_properties_from_params_test.go b/internal/config/gradle/gradle_properties_from_params_test.go new file mode 100644 index 00000000..b411d07d --- /dev/null +++ b/internal/config/gradle/gradle_properties_from_params_test.go @@ -0,0 +1,134 @@ +package gradleconfig + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/bitrise-io/go-utils/v2/log" + "github.com/bitrise-io/go-utils/v2/mocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func Test_gradlePropertiesFromParams(t *testing.T) { + prep := func() (log.Logger, string, string) { + mockLogger := &mocks.Logger{} + mockLogger.On("Infof", mock.Anything).Return() + mockLogger.On("Infof", mock.Anything, mock.Anything).Return() + mockLogger.On("Debugf", mock.Anything).Return() + mockLogger.On("Debugf", mock.Anything, mock.Anything).Return() + mockLogger.On("Errorf", mock.Anything).Return() + mockLogger.On("Errorf", mock.Anything, mock.Anything).Return() + + tmpPath := t.TempDir() + tmpGradleHomeDir := filepath.Join(tmpPath, ".gradle") + _ = os.MkdirAll(tmpGradleHomeDir, 0755) + + propertyFilePath := filepath.Join(tmpGradleHomeDir, "gradle.properties") + + return mockLogger, tmpGradleHomeDir, propertyFilePath + } + + t.Run("Update gradle properties", func(t *testing.T) { + updater := GradlePropertiesUpdater{DefaultOsProxy()} + + mockLogger, tmpGradleHomeDir, propertyFilePath := prep() + + // when + err := updater.UpdateGradleProps( + ActivateForGradleParams{ + Cache: CacheParams{ + Enabled: true, + }, + }, + mockLogger, + tmpGradleHomeDir, + ) + + // then + require.NoError(t, err) + // + data, err := os.ReadFile(propertyFilePath) + require.NoError(t, err) + content := string(data) + assert.Contains(t, content, "org.gradle.caching=true") + }) + + t.Run("Update gradle properties when caching is disabled", func(t *testing.T) { + updater := GradlePropertiesUpdater{DefaultOsProxy()} + + mockLogger, tmpGradleHomeDir, propertyFilePath := prep() + + // when + err := updater.UpdateGradleProps( + ActivateForGradleParams{ + Cache: CacheParams{ + Enabled: false, + }, + }, + mockLogger, + tmpGradleHomeDir, + ) + + // then + require.NoError(t, err) + // + data, err := os.ReadFile(propertyFilePath) + require.NoError(t, err) + content := string(data) + assert.Contains(t, content, "org.gradle.caching=false") + }) + + t.Run("When gradle properties file is missing throws error", func(t *testing.T) { + noFileError := fmt.Errorf("there is no gradle properties file") + osProxy := DefaultOsProxy() + osProxy.ReadFileIfExists = func(string) (string, bool, error) { + return "", false, noFileError + } + updater := GradlePropertiesUpdater{osProxy} + + mockLogger, tmpGradleHomeDir, propertyFilePath := prep() + + // when + err := updater.UpdateGradleProps( + ActivateForGradleParams{ + Cache: CacheParams{ + Enabled: true, + }, + }, + mockLogger, + tmpGradleHomeDir, + ) + + // then + require.EqualError(t, err, fmt.Errorf(ErrFmtGradlePropertiesCheck, propertyFilePath, noFileError).Error()) + }) + + t.Run("When failing to update gradle.properties throws error", func(t *testing.T) { + failedToWriteError := fmt.Errorf("couldn't write gradle properties file") + osProxy := DefaultOsProxy() + osProxy.WriteFile = func(string, []byte, os.FileMode) error { + return failedToWriteError + } + updater := GradlePropertiesUpdater{osProxy} + + mockLogger, tmpGradleHomeDir, propertyFilePath := prep() + + // when + err := updater.UpdateGradleProps( + ActivateForGradleParams{ + Cache: CacheParams{ + Enabled: true, + }, + }, + mockLogger, + tmpGradleHomeDir, + ) + + // then + require.EqualError(t, err, fmt.Errorf(ErrFmtGradlePropertyWrite, propertyFilePath, failedToWriteError).Error()) + }) +} diff --git a/internal/config/gradle/gradleconfig.go b/internal/config/gradle/gradleconfig.go index 7ba38183..0ab4472b 100644 --- a/internal/config/gradle/gradleconfig.go +++ b/internal/config/gradle/gradleconfig.go @@ -3,95 +3,122 @@ package gradleconfig import ( "bytes" _ "embed" - "errors" "fmt" + "os" + "path/filepath" "text/template" - "github.com/bitrise-io/bitrise-build-cache-cli/internal/config/common" - "github.com/bitrise-io/bitrise-build-cache-cli/internal/consts" + "github.com/bitrise-io/go-utils/v2/log" + "github.com/bitrise-io/go-utils/v2/pathutil" ) //go:embed initd.gradle.kts.gotemplate var gradleTemplateText string +//nolint:gochecknoglobals var ( - errAuthTokenNotProvided = errors.New("AuthToken not provided") - errEndpointURLNotProvided = errors.New("EndpointURL not provided") + errFmtInvalidTemplate = "generate init.gradle: invalid template: %w" + errFmtGradleGeneration = "couldn't generate gradle init content: %w" + errFmtEnsureGradleInitDirExists = "ensure ~/.gradle/init.d exists: %w" + errFmtWritingGradleInitFile = "write bitrise-build-cache.init.gradle.kts to %s, error: %w" ) -type CacheValidationLevel string +// Generate init.gradle content. +// Recommended to save the content into $HOME/.gradle/init.d/ instead of +// overwriting the $HOME/.gradle/init.gradle file. +func (inventory TemplateInventory) GenerateInitGradle(templateProxy TemplateProxy) (string, error) { + tmpl, err := templateProxy.parse("init.gradle", gradleTemplateText) + if err != nil { + return "", fmt.Errorf(errFmtInvalidTemplate, err) + } -//nolint:gochecknoglobals -var ( - CacheValidationLevelNone CacheValidationLevel = "none" - CacheValidationLevelWarning CacheValidationLevel = "warning" - CacheValidationLevelError CacheValidationLevel = "error" -) + resultBuffer := bytes.Buffer{} + if err = templateProxy.execute(tmpl, &resultBuffer, inventory); err != nil { + return "", err + } -type Preferences struct { - IsDependencyOnly bool - IsPushEnabled bool - CacheLevelValidation CacheValidationLevel - IsAnalyticsEnabled bool - IsDebugEnabled bool + return resultBuffer.String(), nil } -type templateInventory struct { - IsDependencyOnly bool - AuthToken string - CacheEndpointURLWithPort string - CachePluginVersion string - IsPushEnabled bool - IsDebugEnabled bool - ValidationLevel string - IsAnalyticsEnabled bool - AnalyticsPluginVersion string - AnalyticsEndpoint string - AnalyticsPort int - AnalyticsHTTPEndpoint string - // Metadata - CacheConfigMetadata common.CacheConfigMetadata -} +func (inventory TemplateInventory) WriteToGradleInit( + logger log.Logger, + gradleHomePath string, + osProxy OsProxy, + templateProxy TemplateProxy, +) error { + logger.Infof("(i) Ensure ~/.gradle and ~/.gradle/init.d directories exist") + gradleInitDPath := filepath.Join(gradleHomePath, "init.d") + err := osProxy.MkdirAll(gradleInitDPath, 0755) //nolint:gomnd,mnd + if err != nil { + return fmt.Errorf(errFmtEnsureGradleInitDirExists, err) + } -// Generate init.gradle content. -// Recommended to save the content into $HOME/.gradle/init.d/ instead of -// overwriting the $HOME/.gradle/init.gradle file. -func GenerateInitGradle(endpointURL, authToken string, preferences Preferences, cacheConfigMetadata common.CacheConfigMetadata) (string, error) { - // required check - if len(authToken) < 1 { - return "", fmt.Errorf("generate init.gradle, error: %w", errAuthTokenNotProvided) + logger.Infof("(i) Generate ~/.gradle/init.d/bitrise-build-cache.init.gradle.kts") + initGradleContent, err := inventory.GenerateInitGradle(templateProxy) + if err != nil { + return fmt.Errorf(errFmtGradleGeneration, err) + } + + logger.Infof("(i) Write ~/.gradle/init.d/bitrise-build-cache.init.gradle.kts") + { + initGradlePath := filepath.Join(gradleInitDPath, "bitrise-build-cache.init.gradle.kts") + err = osProxy.WriteFile(initGradlePath, []byte(initGradleContent), 0755) //nolint:gosec,gomnd,mnd + if err != nil { + return fmt.Errorf(errFmtWritingGradleInitFile, initGradlePath, err) + } } - if len(endpointURL) < 1 { - return "", fmt.Errorf("generate init.gradle, error: %w", errEndpointURLNotProvided) + return nil +} + +type TemplateProxy struct { + parse func(name string, templateText string) (*template.Template, error) + execute func(*template.Template, *bytes.Buffer, TemplateInventory) error +} + +func DefaultTemplateProxy() TemplateProxy { + return TemplateProxy{ + parse: func(name string, templateText string) (*template.Template, error) { + funcMap := template.FuncMap{ + "hasDependencies": TemplateInventory.HasDependencies, + } + + return template.New(name).Funcs(funcMap).Parse(templateText) + }, + execute: func(template *template.Template, buffer *bytes.Buffer, inventory TemplateInventory) error { + return template.Execute(buffer, inventory) + }, } +} + +type OsProxy struct { + ReadFileIfExists func(pth string) (string, bool, error) + MkdirAll func(string, os.FileMode) error + WriteFile func(string, []byte, os.FileMode) error +} - // create inventory - inventory := templateInventory{ - IsDependencyOnly: preferences.IsDependencyOnly, - AuthToken: authToken, - CacheEndpointURLWithPort: endpointURL, - CachePluginVersion: consts.GradleRemoteBuildCachePluginDepVersion, - IsPushEnabled: preferences.IsPushEnabled, - IsDebugEnabled: preferences.IsDebugEnabled, - ValidationLevel: string(preferences.CacheLevelValidation), - IsAnalyticsEnabled: preferences.IsAnalyticsEnabled, - AnalyticsPluginVersion: consts.GradleAnalyticsPluginDepVersion, - AnalyticsEndpoint: consts.GradleAnalyticsEndpoint, - AnalyticsPort: consts.GradleAnalyticsPort, - AnalyticsHTTPEndpoint: consts.GradleAnalyticsHTTPEndpoint, - CacheConfigMetadata: cacheConfigMetadata, +func DefaultOsProxy() OsProxy { + return OsProxy{ + ReadFileIfExists: readFileIfExists, + MkdirAll: os.MkdirAll, + WriteFile: os.WriteFile, } +} - tmpl, err := template.New("init.gradle").Parse(gradleTemplateText) +func readFileIfExists(pth string) (string, bool, error) { + fileContent := "" + isFileExist, err := pathutil.NewPathChecker().IsPathExists(pth) if err != nil { - return "", fmt.Errorf("generate init.gradle: invalid template: %w", err) + return "", false, fmt.Errorf("check if file exists at %s, error: %w", pth, err) } - resultBuffer := bytes.Buffer{} - if err = tmpl.Execute(&resultBuffer, inventory); err != nil { - return "", fmt.Errorf("GenerateInitGradle: %w", err) + if isFileExist { + fContent, err := os.ReadFile(pth) + if err != nil { + return "", false, fmt.Errorf("read file at %s, error: %w", pth, err) + } + fileContent = string(fContent) } - return resultBuffer.String(), nil + return fileContent, isFileExist, nil } diff --git a/internal/config/gradle/gradleconfig_generate_test.go b/internal/config/gradle/gradleconfig_generate_test.go new file mode 100644 index 00000000..784fd9c7 --- /dev/null +++ b/internal/config/gradle/gradleconfig_generate_test.go @@ -0,0 +1,195 @@ +package gradleconfig + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_GenerateInitGradle(t *testing.T) { + tests := []struct { + name string + inventory TemplateInventory + want string + wantErr string + }{ + { + name: "No plugins", + inventory: TemplateInventory{ + Common: PluginCommonTemplateInventory{ + AuthToken: "AuthTokenValue", + Debug: true, + AppSlug: "AppSlugValue", + CIProvider: "CIProviderValue", + }, + Cache: CacheTemplateInventory{ + Usage: UsageLevelNone, + }, + Analytics: AnalyticsTemplateInventory{ + Usage: UsageLevelNone, + }, + TestDistro: TestDistroTemplateInventory{ + Usage: UsageLevelNone, + }, + }, + want: expectedNoPluginActivated, + wantErr: "", + }, + { + name: "Dep only plugins", + inventory: TemplateInventory{ + Common: PluginCommonTemplateInventory{ + AuthToken: "AuthTokenValue", + Debug: true, + AppSlug: "AppSlugValue", + CIProvider: "CIProviderValue", + }, + Cache: CacheTemplateInventory{ + Usage: UsageLevelDependency, + Version: "CacheVersionValue", + }, + Analytics: AnalyticsTemplateInventory{ + Usage: UsageLevelDependency, + Version: "AnalyticsVersionValue", + }, + TestDistro: TestDistroTemplateInventory{ + Usage: UsageLevelDependency, + Version: "TestDistroVersionValue", + }, + }, + want: expectedDepOnlyPlugins, + wantErr: "", + }, + { + name: "Activated plugins gets values from inventory", + inventory: TemplateInventory{ + Common: PluginCommonTemplateInventory{ + AuthToken: "AuthTokenValue", + Debug: true, + AppSlug: "AppSlugValue", + CIProvider: "CIProviderValue", + }, + Cache: CacheTemplateInventory{ + Usage: UsageLevelEnabled, + Version: "CacheVersionValue", + EndpointURLWithPort: "CacheEndpointURLValue", + IsPushEnabled: true, + ValidationLevel: "ValidationLevelValue", + }, + Analytics: AnalyticsTemplateInventory{ + Usage: UsageLevelEnabled, + Version: "AnalyticsVersionValue", + Endpoint: "AnalyticsEndpointURLValue", + Port: 123, + HTTPEndpoint: "AnalyticsHttpEndpointValue", + }, + TestDistro: TestDistroTemplateInventory{ + Usage: UsageLevelEnabled, + Version: "TestDistroVersionValue", + Endpoint: "TestDistroEndpointValue", + KvEndpoint: "TestDistroKvEndpointValue", + Port: 321, + LogLevel: "TestDistroLogLevelValue", + }, + }, + want: expectedAllPlugins, + wantErr: "", + }, + } + for _, tt := range tests { //nolint:varnamelen + t.Run(tt.name, func(t *testing.T) { + got, err := tt.inventory.GenerateInitGradle(DefaultTemplateProxy()) + if tt.wantErr != "" { + require.EqualError(t, err, tt.wantErr) + } else { + require.NoError(t, err) + } + assert.Equal(t, tt.want, got) + }) + } +} + +const expectedImports = `import io.bitrise.gradle.cache.BitriseBuildCache +import io.bitrise.gradle.cache.BitriseBuildCacheServiceFactory` + +const expectedRepositories = ` repositories { + mavenLocal() + maven { + name = "artifactRegistry" + url = uri("https://us-maven.pkg.dev/ip-build-cache-prod/build-cache-maven") + } + maven { + name = "gradlePlugins" + url = uri("https://plugins.gradle.org/m2/") + } + mavenCentral() + google() + maven { + name = "jitpackIO" + url = uri("https://jitpack.io") + } + }` + +const expectedDependencies = ` dependencies { + classpath("io.bitrise.gradle:gradle-analytics:AnalyticsVersionValue") + classpath("io.bitrise.gradle:remote-cache:CacheVersionValue") + classpath("io.bitrise.gradle:test-distribution:TestDistroVersionValue") + }` + +const expectedNoPluginActivated = "\ninitscript {\n" + expectedRepositories + "\n}" + +const expectedDepOnlyPlugins = "\ninitscript {\n" + expectedRepositories + "\n" + expectedDependencies + "\n}" + +const expectedAllPlugins = expectedImports + + "\n\ninitscript {\n" + + expectedRepositories + "\n" + + expectedDependencies + "\n}" + + ` +settingsEvaluated { + buildCache { + local { + isEnabled = false + } + + registerBuildCacheService(BitriseBuildCache::class.java, BitriseBuildCacheServiceFactory::class.java) + remote(BitriseBuildCache::class.java) { + endpoint = "CacheEndpointURLValue" + authToken = "AuthTokenValue" + isPush = true + debug = true + blobValidationLevel = "ValidationLevelValue" + collectMetadata = false + } + } + rootProject { + apply() + extensions.configure{ + endpoint.set("AnalyticsEndpointURLValue:123") + httpEndpoint.set("AnalyticsHttpEndpointValue") + authToken.set("AuthTokenValue") + dumpEventsToFiles.set(true) + debug.set(true) + enabled.set(true) + + providerName.set("CIProviderValue") + + bitrise { + appSlug.set("AppSlugValue") + } + } + } +} +rootProject { + extensions.create("rbe", io.bitrise.gradle.rbe.RBEPluginExtension::class.java).with { + endpoint.set("TestDistroEndpointValue:321") + kvEndpoint.set("TestDistroKvEndpointValue:321") + authToken.set("AuthTokenValue") + logLevel.set("TestDistroLogLevelValue") + bitrise { + appSlug.set("AppSlugValue") + } + } + + apply() +}` diff --git a/internal/config/gradle/gradleconfig_test.go b/internal/config/gradle/gradleconfig_test.go deleted file mode 100644 index 2d01a899..00000000 --- a/internal/config/gradle/gradleconfig_test.go +++ /dev/null @@ -1,362 +0,0 @@ -package gradleconfig - -import ( - _ "embed" - "testing" - - "github.com/bitrise-io/bitrise-build-cache-cli/internal/config/common" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestGenerateInitGradle(t *testing.T) { - type args struct { - endpointURL string - authToken string - userPrefs Preferences - cacheConfigMetadata common.CacheConfigMetadata - } - tests := []struct { - name string - args args - want string - wantErr string - }{ - { - name: "No Auth Token provided", - args: args{ - endpointURL: "grpcs://bitrise-accelerate.services.bitrise.io", - }, - want: "", - wantErr: "generate init.gradle, error: AuthToken not provided", - }, - { - name: "No EndpointURL provided", - args: args{ - authToken: "AuthT0ken", - }, - want: "", - wantErr: "generate init.gradle, error: EndpointURL not provided", - }, - { - name: "MetricsEnabled=false", - args: args{ - endpointURL: "grpcs://bitrise-accelerate.services.bitrise.io", - authToken: "AuthT0ken", - userPrefs: Preferences{ - IsPushEnabled: true, - CacheLevelValidation: CacheValidationLevelWarning, - IsAnalyticsEnabled: false, - IsDebugEnabled: true, - }, - cacheConfigMetadata: common.CacheConfigMetadata{ - CIProvider: "BestCI", - RepoURL: "https://github.com/some/repo", - // Bitrise CI specific - BitriseAppID: "BitriseAppID1", - }, - }, - want: expectedInitScriptWithoutMetrics, - wantErr: "", - }, - { - name: "MetricsEnabled=true", - args: args{ - endpointURL: "grpcs://bitrise-accelerate.services.bitrise.io", - authToken: "AuthT0ken", - userPrefs: Preferences{ - IsPushEnabled: true, - CacheLevelValidation: CacheValidationLevelWarning, - IsAnalyticsEnabled: true, - IsDebugEnabled: true, - }, - cacheConfigMetadata: common.CacheConfigMetadata{ - CIProvider: "BestCI", - RepoURL: "https://github.com/some/repo", - // Bitrise CI specific - BitriseAppID: "BitriseAppID1", - }, - }, - want: expectedInitScriptWithMetrics, - wantErr: "", - }, - { - name: "MetricsEnabled=true but empty metadata", - args: args{ - endpointURL: "grpcs://bitrise-accelerate.services.bitrise.io", - authToken: "AuthT0ken", - userPrefs: Preferences{ - IsPushEnabled: true, - CacheLevelValidation: CacheValidationLevelWarning, - IsAnalyticsEnabled: true, - IsDebugEnabled: true, - }, - cacheConfigMetadata: common.CacheConfigMetadata{}, - }, - want: expectedInitScriptWithMetricsButNoMetadata, - wantErr: "", - }, - { - name: "Push disabled, debug enabled, metrics disabled", - args: args{ - endpointURL: "grpcs://bitrise-accelerate.services.bitrise.io", - authToken: "AuthT0ken", - userPrefs: Preferences{ - IsPushEnabled: false, - CacheLevelValidation: CacheValidationLevelError, - IsAnalyticsEnabled: false, - IsDebugEnabled: true, - }, - cacheConfigMetadata: common.CacheConfigMetadata{}, - }, - want: expectedInitScriptNoPushYesDebugNoMetrics, - }, - { - name: "Push enabled, debug disabled, metrics disabled", - args: args{ - endpointURL: "grpcs://bitrise-accelerate.services.bitrise.io", - authToken: "AuthT0ken", - userPrefs: Preferences{ - IsPushEnabled: true, - CacheLevelValidation: CacheValidationLevelError, - IsAnalyticsEnabled: false, - IsDebugEnabled: false, - }, - cacheConfigMetadata: common.CacheConfigMetadata{}, - }, - want: expectedInitScriptYesPushNoDebugNoMetrics, - }, - } - for _, tt := range tests { //nolint:varnamelen - t.Run(tt.name, func(t *testing.T) { - got, err := GenerateInitGradle(tt.args.endpointURL, tt.args.authToken, tt.args.userPrefs, tt.args.cacheConfigMetadata) - if tt.wantErr != "" { - require.EqualError(t, err, tt.wantErr) - } else { - require.NoError(t, err) - } - assert.Equal(t, tt.want, got) - }) - } -} - -const expectedInitScriptWithMetrics = `import io.bitrise.gradle.cache.BitriseBuildCache -import io.bitrise.gradle.cache.BitriseBuildCacheServiceFactory - -initscript { - repositories { - mavenLocal() - maven(url="https://us-maven.pkg.dev/ip-build-cache-prod/build-cache-maven") - maven(url="https://plugins.gradle.org/m2/") - mavenCentral() - google() - maven(url="https://jitpack.io") - } - dependencies { - classpath("io.bitrise.gradle:remote-cache:1.2.19") - classpath("io.bitrise.gradle:gradle-analytics:2.1.28") - } -} - -settingsEvaluated { - buildCache { - local { - isEnabled = false - } - - registerBuildCacheService(BitriseBuildCache::class.java, BitriseBuildCacheServiceFactory::class.java) - remote(BitriseBuildCache::class.java) { - endpoint = "grpcs://bitrise-accelerate.services.bitrise.io" - authToken = "AuthT0ken" - isEnabled = true - isPush = true - debug = true - blobValidationLevel = "warning" - collectMetadata = false - } - } -} - -rootProject { - apply() - - extensions.configure{ - endpoint.set("gradle-analytics.services.bitrise.io:443") - httpEndpoint.set("https://gradle-sink.services.bitrise.io") - authToken.set("AuthT0ken") - dumpEventsToFiles.set(true) - debug.set(true) - enabled.set(true) - - providerName.set("BestCI") - - bitrise { - appSlug.set("BitriseAppID1") - } - } -} -` - -const expectedInitScriptWithMetricsButNoMetadata = `import io.bitrise.gradle.cache.BitriseBuildCache -import io.bitrise.gradle.cache.BitriseBuildCacheServiceFactory - -initscript { - repositories { - mavenLocal() - maven(url="https://us-maven.pkg.dev/ip-build-cache-prod/build-cache-maven") - maven(url="https://plugins.gradle.org/m2/") - mavenCentral() - google() - maven(url="https://jitpack.io") - } - dependencies { - classpath("io.bitrise.gradle:remote-cache:1.2.19") - classpath("io.bitrise.gradle:gradle-analytics:2.1.28") - } -} - -settingsEvaluated { - buildCache { - local { - isEnabled = false - } - - registerBuildCacheService(BitriseBuildCache::class.java, BitriseBuildCacheServiceFactory::class.java) - remote(BitriseBuildCache::class.java) { - endpoint = "grpcs://bitrise-accelerate.services.bitrise.io" - authToken = "AuthT0ken" - isEnabled = true - isPush = true - debug = true - blobValidationLevel = "warning" - collectMetadata = false - } - } -} - -rootProject { - apply() - - extensions.configure{ - endpoint.set("gradle-analytics.services.bitrise.io:443") - httpEndpoint.set("https://gradle-sink.services.bitrise.io") - authToken.set("AuthT0ken") - dumpEventsToFiles.set(true) - debug.set(true) - enabled.set(true) - - providerName.set("") - - bitrise { - } - } -} -` - -const expectedInitScriptWithoutMetrics = `import io.bitrise.gradle.cache.BitriseBuildCache -import io.bitrise.gradle.cache.BitriseBuildCacheServiceFactory - -initscript { - repositories { - mavenLocal() - maven(url="https://us-maven.pkg.dev/ip-build-cache-prod/build-cache-maven") - maven(url="https://plugins.gradle.org/m2/") - mavenCentral() - google() - maven(url="https://jitpack.io") - } - dependencies { - classpath("io.bitrise.gradle:remote-cache:1.2.19") - } -} - -settingsEvaluated { - buildCache { - local { - isEnabled = false - } - - registerBuildCacheService(BitriseBuildCache::class.java, BitriseBuildCacheServiceFactory::class.java) - remote(BitriseBuildCache::class.java) { - endpoint = "grpcs://bitrise-accelerate.services.bitrise.io" - authToken = "AuthT0ken" - isEnabled = true - isPush = true - debug = true - blobValidationLevel = "warning" - } - } -} -` - -const expectedInitScriptNoPushYesDebugNoMetrics = `import io.bitrise.gradle.cache.BitriseBuildCache -import io.bitrise.gradle.cache.BitriseBuildCacheServiceFactory - -initscript { - repositories { - mavenLocal() - maven(url="https://us-maven.pkg.dev/ip-build-cache-prod/build-cache-maven") - maven(url="https://plugins.gradle.org/m2/") - mavenCentral() - google() - maven(url="https://jitpack.io") - } - dependencies { - classpath("io.bitrise.gradle:remote-cache:1.2.19") - } -} - -settingsEvaluated { - buildCache { - local { - isEnabled = false - } - - registerBuildCacheService(BitriseBuildCache::class.java, BitriseBuildCacheServiceFactory::class.java) - remote(BitriseBuildCache::class.java) { - endpoint = "grpcs://bitrise-accelerate.services.bitrise.io" - authToken = "AuthT0ken" - isEnabled = true - isPush = false - debug = true - blobValidationLevel = "error" - } - } -} -` - -const expectedInitScriptYesPushNoDebugNoMetrics = `import io.bitrise.gradle.cache.BitriseBuildCache -import io.bitrise.gradle.cache.BitriseBuildCacheServiceFactory - -initscript { - repositories { - mavenLocal() - maven(url="https://us-maven.pkg.dev/ip-build-cache-prod/build-cache-maven") - maven(url="https://plugins.gradle.org/m2/") - mavenCentral() - google() - maven(url="https://jitpack.io") - } - dependencies { - classpath("io.bitrise.gradle:remote-cache:1.2.19") - } -} - -settingsEvaluated { - buildCache { - local { - isEnabled = false - } - - registerBuildCacheService(BitriseBuildCache::class.java, BitriseBuildCacheServiceFactory::class.java) - remote(BitriseBuildCache::class.java) { - endpoint = "grpcs://bitrise-accelerate.services.bitrise.io" - authToken = "AuthT0ken" - isEnabled = true - isPush = true - debug = false - blobValidationLevel = "error" - } - } -} -` diff --git a/internal/config/gradle/gradleconfig_write_test.go b/internal/config/gradle/gradleconfig_write_test.go new file mode 100644 index 00000000..8188c6ce --- /dev/null +++ b/internal/config/gradle/gradleconfig_write_test.go @@ -0,0 +1,121 @@ +package gradleconfig + +import ( + "bytes" + "errors" + "os" + "path/filepath" + "testing" + "text/template" + + "github.com/bitrise-io/go-utils/v2/log" + "github.com/bitrise-io/go-utils/v2/mocks" + "github.com/bitrise-io/go-utils/v2/pathutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func Test_writeGradleInitGradle(t *testing.T) { + prep := func() (log.Logger, string) { + mockLogger := &mocks.Logger{} + mockLogger.On("Infof", mock.Anything).Return() + mockLogger.On("Infof", mock.Anything, mock.Anything).Return() + mockLogger.On("Debugf", mock.Anything).Return() + mockLogger.On("Debugf", mock.Anything, mock.Anything).Return() + mockLogger.On("Errorf", mock.Anything).Return() + mockLogger.On("Errorf", mock.Anything, mock.Anything).Return() + tmpPath := t.TempDir() + tmpGradleHomeDir := filepath.Join(tmpPath, ".gradle") + + return mockLogger, tmpGradleHomeDir + } + + t.Run("writes the gradle init file", func(t *testing.T) { + mockLogger, tmpGradleHomeDir := prep() + + inventory := TemplateInventory{} + + // when + err := inventory.WriteToGradleInit(mockLogger, tmpGradleHomeDir, DefaultOsProxy(), DefaultTemplateProxy()) + + // then + require.NoError(t, err) + // + isInitFileExists, err := pathutil.NewPathChecker().IsPathExists(filepath.Join(tmpGradleHomeDir, "init.d", "bitrise-build-cache.init.gradle.kts")) + require.NoError(t, err) + assert.True(t, isInitFileExists) + }) + + t.Run("when can't make directories throws error", func(t *testing.T) { + mockLogger, tmpGradleHomeDir := prep() + + inventory := TemplateInventory{} + expectedError := errors.New("failed to create directories") + osProxy := OsProxy{ + MkdirAll: func(string, os.FileMode) error { return expectedError }, + } + + // when + err := inventory.WriteToGradleInit(mockLogger, tmpGradleHomeDir, osProxy, DefaultTemplateProxy()) + + // then + require.ErrorIs(t, err, expectedError) + }) + + t.Run("when template parsing fails throws error", func(t *testing.T) { + mockLogger, tmpGradleHomeDir := prep() + + inventory := TemplateInventory{} + expectedError := errors.New("failed to parse template") + templateProxy := TemplateProxy{ + parse: func(string, string) (*template.Template, error) { + return nil, expectedError + }, + } + + // when + err := inventory.WriteToGradleInit(mockLogger, tmpGradleHomeDir, DefaultOsProxy(), templateProxy) + + // then + require.ErrorIs(t, err, expectedError) + }) + + t.Run("when template execution fails throws error", func(t *testing.T) { + mockLogger, tmpGradleHomeDir := prep() + + inventory := TemplateInventory{} + expectedError := errors.New("failed to execute template") + templateProxy := TemplateProxy{ + parse: DefaultTemplateProxy().parse, + execute: func(*template.Template, *bytes.Buffer, TemplateInventory) error { + return expectedError + }, + } + + // when + err := inventory.WriteToGradleInit(mockLogger, tmpGradleHomeDir, DefaultOsProxy(), templateProxy) + + // then + require.ErrorIs(t, err, expectedError) + }) + + t.Run("when writing init.gradle fails throws error", func(t *testing.T) { + mockLogger, tmpGradleHomeDir := prep() + + inventory := TemplateInventory{} + expectedError := errors.New("failed to write init.gradle") + osProxy := OsProxy{ + MkdirAll: DefaultOsProxy().MkdirAll, + WriteFile: func(string, []byte, os.FileMode) error { + return expectedError + }, + } + + // when + err := inventory.WriteToGradleInit(mockLogger, tmpGradleHomeDir, osProxy, DefaultTemplateProxy()) + + // then + require.ErrorIs(t, err, expectedError) + }) +} diff --git a/internal/config/gradle/initd.gradle.kts.gotemplate b/internal/config/gradle/initd.gradle.kts.gotemplate index 7eafe905..d4f66dcf 100644 --- a/internal/config/gradle/initd.gradle.kts.gotemplate +++ b/internal/config/gradle/initd.gradle.kts.gotemplate @@ -1,24 +1,42 @@ +{{- if eq .Cache.Usage "enabled" -}} import io.bitrise.gradle.cache.BitriseBuildCache -import io.bitrise.gradle.cache.BitriseBuildCacheServiceFactory - +import io.bitrise.gradle.cache.BitriseBuildCacheServiceFactory +{{ end }} initscript { repositories { mavenLocal() - maven(url="https://us-maven.pkg.dev/ip-build-cache-prod/build-cache-maven") - maven(url="https://plugins.gradle.org/m2/") + maven { + name = "artifactRegistry" + url = uri("https://us-maven.pkg.dev/ip-build-cache-prod/build-cache-maven") + } + maven { + name = "gradlePlugins" + url = uri("https://plugins.gradle.org/m2/") + } mavenCentral() google() - maven(url="https://jitpack.io") + maven { + name = "jitpackIO" + url = uri("https://jitpack.io") + } } + {{- if hasDependencies . }} dependencies { - classpath("io.bitrise.gradle:remote-cache:{{ .CachePluginVersion }}") - {{- if .IsAnalyticsEnabled }} - classpath("io.bitrise.gradle:gradle-analytics:{{ .AnalyticsPluginVersion }}") + {{- if eq .Analytics.Usage "dependency" "enabled" }} + classpath("io.bitrise.gradle:gradle-analytics:{{ .Analytics.Version }}") + {{- end }} + {{- if eq .Cache.Usage "dependency" "enabled" }} + classpath("io.bitrise.gradle:remote-cache:{{ .Cache.Version }}") + {{- end }} + {{- if eq .TestDistro.Usage "dependency" "enabled" }} + classpath("io.bitrise.gradle:test-distribution:{{ .TestDistro.Version }}") {{- end }} } + {{- end }} } - +{{- if or (eq .Cache.Usage "enabled") (eq .Analytics.Usage "enabled") }} settingsEvaluated { + {{- if eq .Cache.Usage "enabled" }} buildCache { local { isEnabled = false @@ -26,39 +44,52 @@ settingsEvaluated { registerBuildCacheService(BitriseBuildCache::class.java, BitriseBuildCacheServiceFactory::class.java) remote(BitriseBuildCache::class.java) { - endpoint = "{{ .CacheEndpointURLWithPort }}" - authToken = "{{ .AuthToken }}" - isEnabled = {{ not .IsDependencyOnly }} - isPush = {{ .IsPushEnabled }} - debug = {{ .IsDebugEnabled }} - blobValidationLevel = "{{ .ValidationLevel }}" - {{- if .IsAnalyticsEnabled }} + endpoint = "{{ .Cache.EndpointURLWithPort }}" + authToken = "{{ .Common.AuthToken }}" + isPush = {{ .Cache.IsPushEnabled }} + debug = {{ .Common.Debug }} + blobValidationLevel = "{{ .Cache.ValidationLevel }}" + {{- if eq .Analytics.Usage "dependency" "enabled" }} collectMetadata = false {{- end }} } } -} + {{- end }} + {{- if eq .Analytics.Usage "enabled" }} + rootProject { + apply() + extensions.configure{ + endpoint.set("{{ .Analytics.Endpoint }}:{{ .Analytics.Port }}") + httpEndpoint.set("{{ .Analytics.HTTPEndpoint }}") + authToken.set("{{ .Common.AuthToken }}") + dumpEventsToFiles.set({{ .Common.Debug }}) + debug.set({{ .Common.Debug }}) + enabled.set(true) -{{- if .IsAnalyticsEnabled }} + providerName.set("{{ .Common.CIProvider }}") + bitrise { + {{- if .Common.AppSlug }} + appSlug.set("{{ .Common.AppSlug }}") + {{- end }} + } + } + } + {{- end }} +} +{{- end -}} +{{- if eq .TestDistro.Usage "enabled" }} rootProject { - apply() - - extensions.configure{ - endpoint.set("{{ .AnalyticsEndpoint }}:{{ .AnalyticsPort }}") - httpEndpoint.set("{{ .AnalyticsHTTPEndpoint }}") - authToken.set("{{ .AuthToken }}") - dumpEventsToFiles.set({{ .IsDebugEnabled }}) - debug.set({{ .IsDebugEnabled }}) - enabled.set({{ not .IsDependencyOnly }}) - - providerName.set("{{ .CacheConfigMetadata.CIProvider }}") - + extensions.create("rbe", io.bitrise.gradle.rbe.RBEPluginExtension::class.java).with { + endpoint.set("{{ .TestDistro.Endpoint }}:{{ .TestDistro.Port }}") + kvEndpoint.set("{{ .TestDistro.KvEndpoint }}:{{ .TestDistro.Port }}") + authToken.set("{{ .Common.AuthToken }}") + logLevel.set("{{ .TestDistro.LogLevel }}") bitrise { - {{- if .CacheConfigMetadata.BitriseAppID }} - appSlug.set("{{ .CacheConfigMetadata.BitriseAppID }}") - {{- end }} + appSlug.set("{{ .Common.AppSlug }}") } } + + apply() } -{{- end }} +{{- end -}} \ No newline at end of file diff --git a/internal/consts/consts.go b/internal/consts/consts.go index 70bd7c9b..a93f640c 100644 --- a/internal/consts/consts.go +++ b/internal/consts/consts.go @@ -39,4 +39,7 @@ const ( // Gradle Test Distribution Plugin version GradleTestDistributionPluginDepVersion = "2.1.24" + GradleTestDistributionEndpoint = "grpcs://remote-execution-ord.services.bitrise.io" + GradleTestDistributionKvEndpoint = "grpcs://build-cache-api-ord.services.bitrise.io" + GradleTestDistributionPort = 443 ) diff --git a/internal/gradle/plugin.go b/internal/gradle/plugin.go index 4b9ab460..06c23f52 100644 --- a/internal/gradle/plugin.go +++ b/internal/gradle/plugin.go @@ -7,10 +7,12 @@ import ( "strings" "github.com/bitrise-io/bitrise-build-cache-cli/internal/consts" + "github.com/bitrise-io/go-utils/v2/log" ) const ( bitriseGradlePluginGroup = "io.bitrise.gradle" + WarnNoHome = "Could not determine home directory, falling back to $PWD, error: %s" ) type PluginFile struct { @@ -47,10 +49,11 @@ func (gf *PluginFile) dirPath() string { ) } -func (gf *PluginFile) absoluteDirPath() string { +func (gf *PluginFile) absoluteDirPath(logger log.Logger) string { home, err := os.UserHomeDir() if err != nil { home = os.Getenv("PWD") + logger.Warnf(WarnNoHome, err) } return filepath.Join(home, ".m2", "repository", gf.dirPath()) diff --git a/internal/gradle/plugin_cacher.go b/internal/gradle/plugin_cacher.go index 659e31bd..4d4cfcf7 100644 --- a/internal/gradle/plugin_cacher.go +++ b/internal/gradle/plugin_cacher.go @@ -42,8 +42,8 @@ func (pluginCacher PluginCacher) CachePlugins( for _, file := range plugin.files() { // Try to fetch from cache - if downloaded, err := pluginCacher.fetchFromCache(ctx, kvClient, file); err == nil { - if !downloaded { + if skipped, err := pluginCacher.fetchFromCache(ctx, kvClient, file, logger); err == nil { + if !skipped { logger.Debugf("(i) " + file.name() + " fetched from kv cache") } else { logger.Debugf("(i) " + file.name() + " was already in the local repository") @@ -64,7 +64,7 @@ func (pluginCacher PluginCacher) CachePlugins( logger.Debugf("(i) " + file.name() + " fetched from artifact repositories: " + source) // Upload to cache if fetched from repositories - if err := pluginCacher.cache(ctx, kvClient, file); err != nil { + if err := pluginCacher.cache(ctx, kvClient, file, logger); err != nil { errs = append(errs, err) return @@ -90,10 +90,11 @@ func (pluginCacher PluginCacher) fetchFromCache( ctx context.Context, kvClient *kv.Client, file PluginFile, + logger log.Logger, ) (bool, error) { downloaded, err := kvClient.DownloadFile( ctx, - filepath.Join(file.absoluteDirPath(), file.name()), + filepath.Join(file.absoluteDirPath(logger), file.name()), file.key(), 0, true, @@ -112,10 +113,11 @@ func (pluginCacher PluginCacher) cache( ctx context.Context, kvClient *kv.Client, file PluginFile, + logger log.Logger, ) error { err := kvClient.UploadFileToBuildCache( ctx, - filepath.Join(file.absoluteDirPath(), file.name()), + filepath.Join(file.absoluteDirPath(logger), file.name()), file.key(), ) diff --git a/internal/gradle/plugin_file_downloader.go b/internal/gradle/plugin_file_downloader.go index 39fc2c94..c7590e22 100644 --- a/internal/gradle/plugin_file_downloader.go +++ b/internal/gradle/plugin_file_downloader.go @@ -43,10 +43,10 @@ func (downloader PluginFileDownloader) Download() error { } // Create the file - if err := os.MkdirAll(downloader.file.absoluteDirPath(), os.ModePerm); err != nil { + if err := os.MkdirAll(downloader.file.absoluteDirPath(downloader.logger), os.ModePerm); err != nil { return fmt.Errorf(errFmtCreateFile, err) } - out, err := os.Create(filepath.Join(downloader.file.absoluteDirPath(), downloader.file.name())) + out, err := os.Create(filepath.Join(downloader.file.absoluteDirPath(downloader.logger), downloader.file.name())) if err != nil { return fmt.Errorf(errFmtCreateFile, err) } diff --git a/internal/xcode/mocks/tracker_mock.go b/internal/xcode/mocks/tracker_mock.go index 5ece8ded..c6f86adb 100644 --- a/internal/xcode/mocks/tracker_mock.go +++ b/internal/xcode/mocks/tracker_mock.go @@ -4,10 +4,11 @@ package mocks import ( - "github.com/bitrise-io/bitrise-build-cache-cli/internal/build_cache/kv" - "github.com/bitrise-io/bitrise-build-cache-cli/internal/xcode" "sync" "time" + + "github.com/bitrise-io/bitrise-build-cache-cli/internal/build_cache/kv" + "github.com/bitrise-io/bitrise-build-cache-cli/internal/xcode" ) // Ensure, that StepAnalyticsTrackerMock does implement xcode.StepAnalyticsTracker. diff --git a/proto/build/bazel/remote/execution/v2/remote_execution.pb.go b/proto/build/bazel/remote/execution/v2/remote_execution.pb.go index 80c1333a..d7555b87 100644 --- a/proto/build/bazel/remote/execution/v2/remote_execution.pb.go +++ b/proto/build/bazel/remote/execution/v2/remote_execution.pb.go @@ -21,6 +21,9 @@ package remoteexecution import ( + reflect "reflect" + sync "sync" + longrunningpb "cloud.google.com/go/longrunning/autogen/longrunningpb" semver "github.com/bazelbuild/remote-apis/build/bazel/semver" _ "google.golang.org/genproto/googleapis/api/annotations" @@ -31,8 +34,6 @@ import ( durationpb "google.golang.org/protobuf/types/known/durationpb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" - reflect "reflect" - sync "sync" ) const ( diff --git a/proto/build/bazel/remote/execution/v2/remote_execution_grpc.pb.go b/proto/build/bazel/remote/execution/v2/remote_execution_grpc.pb.go index 743418c0..681e6685 100644 --- a/proto/build/bazel/remote/execution/v2/remote_execution_grpc.pb.go +++ b/proto/build/bazel/remote/execution/v2/remote_execution_grpc.pb.go @@ -7,8 +7,9 @@ package remoteexecution import ( - longrunningpb "cloud.google.com/go/longrunning/autogen/longrunningpb" context "context" + + longrunningpb "cloud.google.com/go/longrunning/autogen/longrunningpb" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" diff --git a/proto/kv_storage/kv_storage.pb.go b/proto/kv_storage/kv_storage.pb.go index 6c7facf7..d2ccafa9 100644 --- a/proto/kv_storage/kv_storage.pb.go +++ b/proto/kv_storage/kv_storage.pb.go @@ -7,11 +7,12 @@ package kv_storage import ( + reflect "reflect" + sync "sync" + bytestream "google.golang.org/genproto/googleapis/bytestream" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" ) const ( diff --git a/proto/kv_storage/kv_storage_grpc.pb.go b/proto/kv_storage/kv_storage_grpc.pb.go index ed6f21ba..b7c46120 100644 --- a/proto/kv_storage/kv_storage_grpc.pb.go +++ b/proto/kv_storage/kv_storage_grpc.pb.go @@ -8,6 +8,7 @@ package kv_storage import ( context "context" + bytestream "google.golang.org/genproto/googleapis/bytestream" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" diff --git a/scripts/generate-dependency-matrix.sh b/scripts/generate-dependency-matrix.sh index d732ad2c..ac0c7dc9 100644 --- a/scripts/generate-dependency-matrix.sh +++ b/scripts/generate-dependency-matrix.sh @@ -20,8 +20,8 @@ git clone https://github.com/bitrise-io/bitrise-build-cache-cli.git git clone https://github.com/bitrise-steplib/bitrise-step-activate-gradle-remote-cache.git export tmp_md="release-table.md" -echo "| Step version | CLI version | Analytics plugin version | Cache plugin version |" >> $tmp_md -echo "|--------------|-------------|--------------------------|----------------------|" >> $tmp_md +echo "| Step version | CLI version | Analytics plugin version | Cache plugin version | Test Distribution plugin version |" >> $tmp_md +echo "|--------------|-------------|--------------------------|----------------------|----------------------------------|" >> $tmp_md find "bitrise-steplib/steps/activate-build-cache-for-gradle" -mindepth 1 -maxdepth 1 -type d | while read -r dir; do @@ -52,7 +52,7 @@ sort -Vr | while read -r step_version; do cd ../bitrise-build-cache-cli git checkout "$cli_version" - go run main.go enable-for gradle + go run main.go activate gradle --cache --test-distribution if [ ! -f "$HOME/.gradle/init.d/bitrise-build-cache.init.gradle.kts" ]; then echo "Gradle build cache not enabled in $HOME/.gradle/init.d/bitrise-build-cache.init.gradle.kts" @@ -62,11 +62,12 @@ sort -Vr | while read -r step_version; do analytics_version=$(grep 'classpath("io.bitrise.gradle:gradle-analytics:' "$HOME/.gradle/init.d/bitrise-build-cache.init.gradle.kts" | sed -n -E 's/.*gradle-analytics:([0-9]+\.[0-9]+\.[0-9]+).*/\1/p') cache_version=$(grep 'classpath("io.bitrise.gradle:remote-cache:' "$HOME/.gradle/init.d/bitrise-build-cache.init.gradle.kts" | sed -n -E 's/.*remote-cache:([0-9]+\.[0-9]+\.[0-9]+).*/\1/p') + test_distro_version=$(grep 'classpath("io.bitrise.gradle:test-distribution:' "$HOME/.gradle/init.d/bitrise-build-cache.init.gradle.kts" | sed -n -E 's/.*test-distribution:([0-9]+\.[0-9]+\.[0-9]+).*/\1/p') - echo "Gradle build cache enabled with analytics version: $analytics_version and cache version: $cache_version" + echo "Gradle build cache enabled with analytics version: $analytics_version, cache version: $cache_version, test-distribution version: $test_distro_version" cd .. - echo "| $step_version | [$cli_version]($CLI_RELEASE_URL_PREFIX/$cli_version) | $analytics_version | $cache_version |" >> $tmp_md + echo "| $step_version | [$cli_version]($CLI_RELEASE_URL_PREFIX/$cli_version) | $analytics_version | $cache_version | $test_distro_version |" >> $tmp_md done popd diff --git a/scripts/update_plugins.sh b/scripts/update_plugins.sh index 301147d7..cbaf1994 100755 --- a/scripts/update_plugins.sh +++ b/scripts/update_plugins.sh @@ -2,7 +2,6 @@ set -e VERSION_FILE="./internal/consts/consts.go" -TEST_FILE="./internal/config/gradle/gradleconfig_test.go" SED_IN_PLACE_COMMAND=(-i) if [[ "$OSTYPE" == "darwin"* ]]; then @@ -45,7 +44,6 @@ update() { # Compare versions and update if the latest is greater if compare_versions "$current_version" "$latest_version"; then sed "${SED_IN_PLACE_COMMAND[@]}" "s/$dep_version_name = \".*\"/$dep_version_name = \"$latest_version\"/" "$VERSION_FILE" - sed "${SED_IN_PLACE_COMMAND[@]}" "s/classpath(\"io.bitrise.gradle:$artifact_name:.*\")/classpath(\"io.bitrise.gradle:$artifact_name:$latest_version\")/" "$TEST_FILE" echo "Updated to version $latest_version" else echo "No update needed. Current version ($current_version) is up-to-date or newer."