Skip to content

[ACI-3750] Add activate command #127

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Jun 19, 2025
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8b75a6d
Add activate command (activating plugins) + minor cleanup on paramete…
Badlazzor Jun 3, 2025
2730ffe
Cover activate with unit tests
Badlazzor Jun 4, 2025
da3de13
Use assignment instead of set for cache params
Badlazzor Jun 4, 2025
118da8c
Create various helper structs and proxies for testing. Update tests.
Badlazzor Jun 10, 2025
5b2d68f
Use envProvider instead of od.getenv directly
Badlazzor Jun 10, 2025
5450c21
Update gradle verification
Badlazzor Jun 10, 2025
aa0882d
Fix cache level usage
Badlazzor Jun 10, 2025
77cfca5
Reset verification metadata
Badlazzor Jun 10, 2025
4d75880
Add test-distribution to verification metadata
Badlazzor Jun 10, 2025
3f4ef40
Update verification metadata
Badlazzor Jun 10, 2025
8fe4308
Update verification metadata
Badlazzor Jun 10, 2025
434030e
Set enabled on analytics in init.gradle
Badlazzor Jun 10, 2025
b8d8b74
Add enabled=true to init gradle text generation when activating analy…
Badlazzor Jun 10, 2025
5c585cb
Update scripts accommodating new plugin
Badlazzor Jun 11, 2025
217c236
Remove test file reintroduced by rebase, add missing repos to tests
Badlazzor Jun 16, 2025
8be8d7b
Add test distribution to plugin caching, rename file to snake_case
Badlazzor Jun 17, 2025
edc37aa
Make test expectations on generated gradle.init file come from parts …
Badlazzor Jun 18, 2025
87a87ef
Update verification metadata to match the one expected by the CI
Badlazzor Jun 18, 2025
873a31e
Clarify already downloaded file ignorance, log PWD fallback
Badlazzor Jun 18, 2025
42aff0a
Move `ActivateForGradleParams` to gradle package, move `ReadFileIfExi…
Badlazzor Jun 18, 2025
d32ce1d
Update expected error in test for activate command
Badlazzor Jun 18, 2025
1e0aea6
Move global activate for gradle param struct to cmd level
Badlazzor Jun 18, 2025
f5f95cd
Remove globals from activate_for_gradle_params.go
Badlazzor Jun 18, 2025
326f851
Remove surplus dependencies in `activateForGradleCmdFn` function params
Badlazzor Jun 18, 2025
3e4ba84
Update e2e tests to use activate instead of enable for gradle
Badlazzor Jun 18, 2025
901b21d
Fix cli calls in yaml (activate-for -> activate)
Badlazzor Jun 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions cmd/activate.go
Original file line number Diff line number Diff line change
@@ -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)
}
113 changes: 113 additions & 0 deletions cmd/activate_for_gradle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
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,
gradleconfig.GlobalActivateForGradleParams.TemplateInventory,
func(inventory gradleconfig.TemplateInventory,
logger log.Logger,
path string,
osProxy gradleconfig.OsProxy,
templateProxy gradleconfig.TemplateProxy,
) error {
return inventory.WriteToGradleInit(logger, path, osProxy, templateProxy)
},
gradleconfig.DefaultGradlePropertiesUpdater(),
); err != nil {
return fmt.Errorf("activate plugins for Gradle: %w", err)
}

logger.TInfof("✅ Bitrise plugins activated")

return nil
},
}

func init() {
activateCmd.AddCommand(activateForGradleCmd)
activateForGradleCmd.Flags().BoolVar(&gradleconfig.GlobalActivateForGradleParams.Cache.Enabled, "cache", gradleconfig.GlobalActivateForGradleParams.Cache.Enabled, "Activate cache plugin. Will override cache-dep.")
activateForGradleCmd.Flags().BoolVar(&gradleconfig.GlobalActivateForGradleParams.Cache.JustDependency, "cache-dep", gradleconfig.GlobalActivateForGradleParams.Cache.JustDependency, "Add cache plugin as a dependency only.")
activateForGradleCmd.Flags().BoolVar(&gradleconfig.GlobalActivateForGradleParams.Cache.PushEnabled, "cache-push", gradleconfig.GlobalActivateForGradleParams.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(&gradleconfig.GlobalActivateForGradleParams.Cache.ValidationLevel, "cache-validation", gradleconfig.GlobalActivateForGradleParams.Cache.ValidationLevel, "Level of cache entry validation for both uploads and downloads. Possible values: none, warning, error")
activateForGradleCmd.Flags().StringVar(&gradleconfig.GlobalActivateForGradleParams.Cache.Endpoint, "cache-endpoint", gradleconfig.GlobalActivateForGradleParams.Cache.Endpoint, "The endpoint can be manually provided here for caching operations.")

activateForGradleCmd.Flags().BoolVar(&gradleconfig.GlobalActivateForGradleParams.Analytics.Enabled, "analytics", gradleconfig.GlobalActivateForGradleParams.Analytics.Enabled, "Activate analytics plugin. Will override analytics-dep.")
activateForGradleCmd.Flags().BoolVar(&gradleconfig.GlobalActivateForGradleParams.Analytics.JustDependency, "analytics-dep", gradleconfig.GlobalActivateForGradleParams.Analytics.JustDependency, "Add analytics plugin as a dependency only.")

activateForGradleCmd.Flags().BoolVar(&gradleconfig.GlobalActivateForGradleParams.TestDistro.Enabled, "test-distribution", gradleconfig.GlobalActivateForGradleParams.TestDistro.Enabled, "Activate test distribution plugin for the provided app slug. Will override test-distribution-dep.")
activateForGradleCmd.Flags().BoolVar(&gradleconfig.GlobalActivateForGradleParams.TestDistro.JustDependency, "test-distribution-dep", gradleconfig.GlobalActivateForGradleParams.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, log.Logger, string, gradleconfig.OsProxy, gradleconfig.TemplateProxy) error,
updater gradleconfig.GradlePropertiesUpdater,
) error {
templateInventory, err := templateInventoryProvider(logger, envProvider, isDebugLogMode)
if err != nil {
return err
}

if err := templateWriter(
templateInventory,
logger,
gradleHomePath,
gradleconfig.DefaultOsProxy(),
gradleconfig.DefaultTemplateProxy(),
); err != nil {
return err
}

if err := updater.UpdateGradleProps(gradleconfig.GlobalActivateForGradleParams, logger, gradleHomePath); err != nil {
return fmt.Errorf(errFmtFailedToUpdateProps, err)
}

return nil
}
193 changes: 193 additions & 0 deletions cmd/activate_for_gradle_cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
//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,
_ log.Logger,
_ string,
_ gradleconfig.OsProxy,
_ gradleconfig.TemplateProxy,
) 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,
log.Logger,
string,
gradleconfig.OsProxy,
gradleconfig.TemplateProxy,
) 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,
log.Logger,
string,
gradleconfig.OsProxy,
gradleconfig.TemplateProxy,
) 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,
log.Logger,
string,
gradleconfig.OsProxy,
gradleconfig.TemplateProxy,
) 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(),
)
})
}
Loading