diff --git a/docs/configuration/overview.md b/docs/configuration/overview.md index 1bb67936..0e74261e 100644 --- a/docs/configuration/overview.md +++ b/docs/configuration/overview.md @@ -73,6 +73,10 @@ All `axion-release-plugin` configuration options: uncommittedChanges.set(false) // permanently disable uncommitted changes check aheadOfRemote.set(false) // permanently disable ahead of remote check } + + // doc: Version / releaseOnlyOnReleaseBranches + releaseOnlyOnReleaseBranches = false + releaseBranchNames = ['master', 'main'] } All `axion-release-plugin` configuration flags: @@ -108,3 +112,9 @@ All `axion-release-plugin` configuration flags: - release.fetchTags - default: false - fetch tags from the remote repository +- release.releaseOnlyOnReleaseBranches + - default: false + - only perform a release on branches that match the `releaseBranchNames` +- release.releaseBranchNames + - default: `['master', 'main']` + - a list of branch names that are considered release branches diff --git a/docs/configuration/version.md b/docs/configuration/version.md index a6bb0814..9f524b90 100644 --- a/docs/configuration/version.md +++ b/docs/configuration/version.md @@ -278,6 +278,30 @@ This rule uses additional parameter `initialPreReleaseIfNotOnPrerelease` versionIncrementer('incrementPrerelease', [initialPreReleaseIfNotOnPrerelease: 'rc1']) } +### releaseOnlyOnReleaseBranches + +You can set this flag to true to prevent releasing on branches that are +not marked as release branches. By default, this flag is set to false. + + scmVersion { + releaseOnlyOnReleaseBranches = true + } + +This flag can also be set via command line: + + ./gradlew release -Prelease.releaseOnlyOnReleaseBranches + +And works well in combination with `releaseBranchNames` option + + scmVersion { + releaseOnlyOnReleaseBranches = true + releaseBranchNames = ['main', 'master'] + } + +or as command line + + ./gradlew release -Prelease.releaseOnlyOnReleaseBranches -Prelease.releaseBranchNames=main,release + ## Decorating Decorating phase happens only when version is read (and deserialized). @@ -367,9 +391,7 @@ Custom version creators can be implemented by creating closure: {version, position -> ...} - version - string version resolved by previous steps -- -position - [ScmPosition](https://github.com/allegro/axion-release-plugin/blob/main/src/main/java/pl/allegro/tech/build/axion/release/domain/scm/ScmPosition.java) -object +- position - [ScmPosition](https://github.com/allegro/axion-release-plugin/blob/main/src/main/java/pl/allegro/tech/build/axion/release/domain/scm/ScmPosition.java) object ### Snapshot @@ -386,9 +408,7 @@ Snapshot creator can be implemented by creating closure: {version, position -> ...} - version - string version resolved by previous steps -- -position - [ScmPosition](https://github.com/allegro/axion-release-plugin/blob/main/src/main/java/pl/allegro/tech/build/axion/release/domain/scm/ScmPosition.java) -object +- position - [ScmPosition](https://github.com/allegro/axion-release-plugin/blob/main/src/main/java/pl/allegro/tech/build/axion/release/domain/scm/ScmPosition.java) object ## Sanitization diff --git a/src/integration/groovy/pl/allegro/tech/build/axion/release/BaseIntegrationTest.groovy b/src/integration/groovy/pl/allegro/tech/build/axion/release/BaseIntegrationTest.groovy index 2cba83ab..771ed37e 100644 --- a/src/integration/groovy/pl/allegro/tech/build/axion/release/BaseIntegrationTest.groovy +++ b/src/integration/groovy/pl/allegro/tech/build/axion/release/BaseIntegrationTest.groovy @@ -25,6 +25,7 @@ class BaseIntegrationTest extends RepositoryBasedTest { """ project.version = scmVersion.version + scmVersion.ignoreGlobalGitConfig = true """) } @@ -48,6 +49,7 @@ class BaseIntegrationTest extends RepositoryBasedTest { try { return gradle().withArguments(args).build() } + finally { def ccDir = new File(temporaryFolder, "build/reports/configuration-cache") if (ccDir.exists() && ccDir.isDirectory()) { diff --git a/src/integration/groovy/pl/allegro/tech/build/axion/release/SimpleIntegrationTest.groovy b/src/integration/groovy/pl/allegro/tech/build/axion/release/SimpleIntegrationTest.groovy index e1ad245a..0a3c89c0 100644 --- a/src/integration/groovy/pl/allegro/tech/build/axion/release/SimpleIntegrationTest.groovy +++ b/src/integration/groovy/pl/allegro/tech/build/axion/release/SimpleIntegrationTest.groovy @@ -13,7 +13,7 @@ import static pl.allegro.tech.build.axion.release.TagPrefixConf.fullPrefix class SimpleIntegrationTest extends BaseIntegrationTest { @Rule - EnvironmentVariables environmentVariablesRule = new EnvironmentVariables(); + EnvironmentVariables environmentVariablesRule = new EnvironmentVariables() def "should return default version on calling currentVersion task on vanilla repo"() { given: @@ -140,4 +140,49 @@ class SimpleIntegrationTest extends BaseIntegrationTest { result.output.contains('Project version: 0.0.1-SNAPSHOT') result.task(":currentVersion").outcome == TaskOutcome.SUCCESS } + + def "should skip release when releaseOnlyOnReleaseBranches is true and current branch is not on releaseBranchNames list"() { + given: + buildFile(""" + scmVersion { + releaseOnlyOnReleaseBranches = true + releaseBranchNames = ['develop', 'release'] + } + """) + + when: + def releaseResult = runGradle('release', '-Prelease.version=1.0.0', '-Prelease.localOnly', '-Prelease.disableChecks') + + then: + releaseResult.task(':release').outcome == TaskOutcome.SUCCESS + releaseResult.output.contains('Release step skipped since \'releaseOnlyOnDefaultBranches\' option is set, and \'master\' was not in \'releaseBranchNames\' list [develop,release]') + } + + def "should skip release when releaseOnlyOnReleaseBranches is set by gradle task property and current branch is not on releaseBranchNames list"() { + given: + buildFile("") + + when: + def releaseResult = runGradle('release', '-Prelease.releaseOnlyOnReleaseBranches', '-Prelease.releaseBranchNames=develop,release', '-Prelease.version=1.0.0', '-Prelease.localOnly', '-Prelease.disableChecks') + + then: + releaseResult.task(':release').outcome == TaskOutcome.SUCCESS + releaseResult.output.contains('Release step skipped since \'releaseOnlyOnDefaultBranches\' option is set, and \'master\' was not in \'releaseBranchNames\' list [develop,release]') + } + + def "should not skip release when releaseOnlyOnReleaseBranches is true when on master branch (default releaseBranches list)"() { + given: + buildFile(""" + scmVersion { + releaseOnlyOnReleaseBranches = true + } + """) + + when: + def releaseResult = runGradle('release', '-Prelease.version=1.0.0', '-Prelease.localOnly', '-Prelease.disableChecks') + + then: + releaseResult.task(':release').outcome == TaskOutcome.SUCCESS + releaseResult.output.contains('Creating tag: ' + fullPrefix() + '1.0.0') + } } diff --git a/src/main/groovy/pl/allegro/tech/build/axion/release/CreateReleaseTask.groovy b/src/main/groovy/pl/allegro/tech/build/axion/release/CreateReleaseTask.groovy index c8715f2a..0ba97aa5 100644 --- a/src/main/groovy/pl/allegro/tech/build/axion/release/CreateReleaseTask.groovy +++ b/src/main/groovy/pl/allegro/tech/build/axion/release/CreateReleaseTask.groovy @@ -1,6 +1,5 @@ package pl.allegro.tech.build.axion.release - import org.gradle.api.tasks.TaskAction import pl.allegro.tech.build.axion.release.domain.Releaser import pl.allegro.tech.build.axion.release.infrastructure.di.VersionResolutionContext @@ -11,6 +10,11 @@ abstract class CreateReleaseTask extends BaseAxionTask { void release() { VersionResolutionContext context = resolutionContext() Releaser releaser = context.releaser() - releaser.release(context.rules()) + ReleaseBranchesConfiguration releaseBranchesConfiguration = new ReleaseBranchesConfiguration( + context.scmService().isReleaseOnlyOnReleaseBranches(), + context.repository().currentPosition().getBranch(), + context.scmService().getReleaseBranchNames() + ) + releaser.release(context.rules(), releaseBranchesConfiguration) } } diff --git a/src/main/groovy/pl/allegro/tech/build/axion/release/ReleaseBranchesConfiguration.groovy b/src/main/groovy/pl/allegro/tech/build/axion/release/ReleaseBranchesConfiguration.groovy new file mode 100644 index 00000000..d4a8ab7f --- /dev/null +++ b/src/main/groovy/pl/allegro/tech/build/axion/release/ReleaseBranchesConfiguration.groovy @@ -0,0 +1,29 @@ +package pl.allegro.tech.build.axion.release + +class ReleaseBranchesConfiguration { + private final boolean releaseOnlyOnReleaseBranches + private final String currentBranch + private final Set releaseBranchNames + + ReleaseBranchesConfiguration( + boolean releaseOnlyOnReleaseBranches, + String currentBranch, + Set releaseBranchNames + ) { + this.releaseOnlyOnReleaseBranches = releaseOnlyOnReleaseBranches + this.currentBranch = currentBranch + this.releaseBranchNames = releaseBranchNames + } + + boolean shouldRelease() { + return releaseOnlyOnReleaseBranches && !releaseBranchNames.contains(currentBranch) + } + + String getCurrentBranch() { + return currentBranch + } + + Set getReleaseBranchNames() { + return releaseBranchNames + } +} diff --git a/src/main/groovy/pl/allegro/tech/build/axion/release/ReleaseTask.groovy b/src/main/groovy/pl/allegro/tech/build/axion/release/ReleaseTask.groovy index 4a64fe69..8ff57718 100644 --- a/src/main/groovy/pl/allegro/tech/build/axion/release/ReleaseTask.groovy +++ b/src/main/groovy/pl/allegro/tech/build/axion/release/ReleaseTask.groovy @@ -15,10 +15,15 @@ abstract class ReleaseTask extends BaseAxionTask { void release() { VersionResolutionContext context = resolutionContext() Releaser releaser = context.releaser() - ScmPushResult result = releaser.releaseAndPush(context.rules()) + ReleaseBranchesConfiguration releaseBranchesConfiguration = new ReleaseBranchesConfiguration( + context.scmService().isReleaseOnlyOnReleaseBranches(), + context.repository().currentPosition().getBranch(), + context.scmService().getReleaseBranchNames() + ) + ScmPushResult result = releaser.releaseAndPush(context.rules(), releaseBranchesConfiguration) if (!result.success) { - def status = result.failureStatus.orElse("Unknown status of push") + def status = result.failureStatus def message = result.remoteMessage.orElse("Unknown error during push") logger.error("remote status: ${status}") logger.error("remote message: ${message}") diff --git a/src/main/groovy/pl/allegro/tech/build/axion/release/domain/BaseExtension.groovy b/src/main/groovy/pl/allegro/tech/build/axion/release/domain/BaseExtension.groovy index 50900c83..50c72a51 100644 --- a/src/main/groovy/pl/allegro/tech/build/axion/release/domain/BaseExtension.groovy +++ b/src/main/groovy/pl/allegro/tech/build/axion/release/domain/BaseExtension.groovy @@ -28,11 +28,15 @@ abstract class BaseExtension { GradleVersion.current() } - protected Provider gradlePropertyBoolean(String name) { + protected Provider> gradlePropertyAsSet(String name) { + return gradleProperty(name).map({ it.tokenize(',') as Set }) + } + + protected Provider gradlePropertyAsBoolean(String name) { return gradleProperty(name).map(Boolean::valueOf) } protected Provider gradlePropertyPresent(String name) { - return gradleProperty(name).map({true}) + return gradleProperty(name).map({ true }) } } diff --git a/src/main/groovy/pl/allegro/tech/build/axion/release/domain/RepositoryConfig.groovy b/src/main/groovy/pl/allegro/tech/build/axion/release/domain/RepositoryConfig.groovy index b4cb661a..c19ea8b7 100644 --- a/src/main/groovy/pl/allegro/tech/build/axion/release/domain/RepositoryConfig.groovy +++ b/src/main/groovy/pl/allegro/tech/build/axion/release/domain/RepositoryConfig.groovy @@ -89,7 +89,7 @@ abstract class RepositoryConfig extends BaseExtension { } Provider overriddenIsClean() { - gradlePropertyBoolean(OVERRIDDEN_IS_CLEAN) + gradlePropertyAsBoolean(OVERRIDDEN_IS_CLEAN) } Provider disableSshAgent() { diff --git a/src/main/groovy/pl/allegro/tech/build/axion/release/domain/VersionConfig.groovy b/src/main/groovy/pl/allegro/tech/build/axion/release/domain/VersionConfig.groovy index 5b66129e..cf1d1282 100644 --- a/src/main/groovy/pl/allegro/tech/build/axion/release/domain/VersionConfig.groovy +++ b/src/main/groovy/pl/allegro/tech/build/axion/release/domain/VersionConfig.groovy @@ -6,6 +6,7 @@ import org.gradle.api.file.Directory import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider +import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.Input import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Nested @@ -33,6 +34,8 @@ abstract class VersionConfig extends BaseExtension { private static final String DEPRECATED_FORCE_VERSION_PROPERTY = 'release.forceVersion' private static final String VERSION_INCREMENTER_PROPERTY = 'release.versionIncrementer' private static final String VERSION_CREATOR_PROPERTY = 'release.versionCreator' + private static final String RELEASE_ONLY_ON_RELEASE_BRANCHES_PROPERTY = 'release.releaseOnlyOnReleaseBranches' + private static final String RELEASE_BRANCH_NAMES_PROPERTY = 'release.releaseBranchNames' @Inject VersionConfig(Directory repositoryDirectory) { @@ -41,6 +44,9 @@ abstract class VersionConfig extends BaseExtension { getIgnoreUncommittedChanges().convention(true) getUseHighestVersion().convention(false) getUnshallowRepoOnCI().convention(false) + getIgnoreGlobalGitConfig().convention(false) + getReleaseBranchNames().convention(gradlePropertyAsSet(RELEASE_BRANCH_NAMES_PROPERTY).orElse(['master', 'main'] as Set)) + getReleaseOnlyOnReleaseBranches().convention(gradlePropertyPresent(RELEASE_ONLY_ON_RELEASE_BRANCHES_PROPERTY).orElse(false)) getReleaseBranchPattern().convention(Pattern.compile('^' + defaultPrefix() + '(/.*)?$')) getSanitizeVersion().convention(true) getCreateReleaseCommit().convention(false) @@ -79,7 +85,13 @@ abstract class VersionConfig extends BaseExtension { abstract Property getIgnoreUncommittedChanges() @Internal - abstract Property getUseHighestVersion(); + abstract SetProperty getReleaseBranchNames() + + @Internal + abstract Property getReleaseOnlyOnReleaseBranches() + + @Internal + abstract Property getIgnoreGlobalGitConfig() @Internal @Incubating @@ -112,6 +124,9 @@ abstract class VersionConfig extends BaseExtension { @Internal abstract Property getReleaseCommitMessage() + @Internal + abstract Property getUseHighestVersion(); + Provider ignoreUncommittedChanges() { gradlePropertyPresent(IGNORE_UNCOMMITTED_CHANGES_PROPERTY) .orElse(ignoreUncommittedChanges) @@ -132,8 +147,8 @@ abstract class VersionConfig extends BaseExtension { Provider forcedVersion() { gradleProperty(FORCE_VERSION_PROPERTY) .orElse(gradleProperty(DEPRECATED_FORCE_VERSION_PROPERTY)) - .map({it.trim()}) - .map({ it.isBlank() ? null : it}) + .map({ it.trim() }) + .map({ it.isBlank() ? null : it }) } Provider versionIncrementerType() { @@ -216,12 +231,12 @@ abstract class VersionConfig extends BaseExtension { Provider versionProvider() { def cachedVersionSupplier = this.cachedVersionSupplier - providers.provider( { cachedVersionSupplier.resolve(this,layout.projectDirectory)}) + providers.provider({ cachedVersionSupplier.resolve(this, layout.projectDirectory) }) } Provider uncachedVersionProvider() { def versionSupplier = this.versionSupplier - providers.provider( { versionSupplier.resolve(this, layout.projectDirectory)}) + providers.provider({ versionSupplier.resolve(this, layout.projectDirectory) }) } @Nested @@ -231,21 +246,21 @@ abstract class VersionConfig extends BaseExtension { @Input String getVersion() { - return versionProvider().map({ it.decoratedVersion}).get() + return versionProvider().map({ it.decoratedVersion }).get() } @Input String getPreviousVersion() { - return versionProvider().map({ it.previousVersion}).get() + return versionProvider().map({ it.previousVersion }).get() } @Input String getUndecoratedVersion() { - return versionProvider().map({ it.undecoratedVersion}).get() + return versionProvider().map({ it.undecoratedVersion }).get() } @Nested ScmPosition getScmPosition() { - return versionProvider().map({it.position}).get() + return versionProvider().map({ it.position }).get() } } diff --git a/src/main/groovy/pl/allegro/tech/build/axion/release/infrastructure/config/ScmPropertiesFactory.groovy b/src/main/groovy/pl/allegro/tech/build/axion/release/infrastructure/config/ScmPropertiesFactory.groovy index fd9a4e70..8900f4cb 100644 --- a/src/main/groovy/pl/allegro/tech/build/axion/release/infrastructure/config/ScmPropertiesFactory.groovy +++ b/src/main/groovy/pl/allegro/tech/build/axion/release/infrastructure/config/ScmPropertiesFactory.groovy @@ -17,7 +17,10 @@ class ScmPropertiesFactory { config.repository.overriddenBranch().getOrNull(), config.repository.overriddenIsClean().getOrNull(), ScmIdentityFactory.create(config.repository, config.repository.disableSshAgent().get()), - config.getUnshallowRepoOnCI().get() + config.getUnshallowRepoOnCI().get(), + config.getReleaseBranchNames().get(), + config.getReleaseOnlyOnReleaseBranches().get(), + config.getIgnoreGlobalGitConfig().get() ) } } diff --git a/src/main/java/pl/allegro/tech/build/axion/release/domain/Releaser.java b/src/main/java/pl/allegro/tech/build/axion/release/domain/Releaser.java index 5fc78d94..9bbfb5f3 100644 --- a/src/main/java/pl/allegro/tech/build/axion/release/domain/Releaser.java +++ b/src/main/java/pl/allegro/tech/build/axion/release/domain/Releaser.java @@ -3,6 +3,7 @@ import com.github.zafarkhaja.semver.Version; import org.gradle.api.logging.Logger; import org.gradle.api.logging.Logging; +import pl.allegro.tech.build.axion.release.ReleaseBranchesConfiguration; import pl.allegro.tech.build.axion.release.domain.hooks.ReleaseHooksRunner; import pl.allegro.tech.build.axion.release.domain.properties.Properties; import pl.allegro.tech.build.axion.release.domain.scm.ScmPushResult; @@ -23,10 +24,21 @@ public Releaser(VersionService versionService, ScmService repository, ReleaseHoo this.hooksRunner = hooksRunner; } - public Optional release(Properties properties) { + public Optional release(Properties properties, ReleaseBranchesConfiguration releaseBranchesConfiguration) { + if (releaseBranchesConfiguration.shouldRelease()) { + String message = String.format( + "Release step skipped since 'releaseOnlyOnDefaultBranches' option is set, and '%s' was not in 'releaseBranchNames' list [%s]", + releaseBranchesConfiguration.getCurrentBranch(), + String.join(",", releaseBranchesConfiguration.getReleaseBranchNames()) + ); + logger.quiet(message); + return Optional.empty(); + } + VersionContext versionContext = versionService.currentVersion( properties.getVersion(), properties.getTag(), properties.getNextVersion() ); + Version version = versionContext.getVersion(); if (versionContext.isSnapshot()) { @@ -43,11 +55,14 @@ public Optional release(Properties properties) { logger.quiet("Working on released version " + version + ", nothing to release"); return Optional.empty(); } - } - public ScmPushResult releaseAndPush(Properties rules) { - Optional releasedTagName = release(rules); + public ScmPushResult releaseAndPush(Properties rules, ReleaseBranchesConfiguration releaseBranchesConfiguration) { + Optional releasedTagName = release(rules, releaseBranchesConfiguration); + + if (releasedTagName.isEmpty()) { + return new ScmPushResult(true, Optional.empty(), Optional.empty()); + } ScmPushResult result = pushRelease(); diff --git a/src/main/java/pl/allegro/tech/build/axion/release/domain/scm/ScmProperties.java b/src/main/java/pl/allegro/tech/build/axion/release/domain/scm/ScmProperties.java index f202c510..a264aa65 100644 --- a/src/main/java/pl/allegro/tech/build/axion/release/domain/scm/ScmProperties.java +++ b/src/main/java/pl/allegro/tech/build/axion/release/domain/scm/ScmProperties.java @@ -2,6 +2,7 @@ import java.io.File; import java.util.Optional; +import java.util.Set; public class ScmProperties { @@ -16,6 +17,9 @@ public class ScmProperties { private final Boolean overriddenIsClean; private final ScmIdentity identity; private final Boolean unshallowRepoOnCI; + private final Set releaseBranchNames; + private final boolean releaseOnlyOnReleaseBranches; + private final boolean ignoreGlobalGitConfig; public ScmProperties( String type, @@ -28,7 +32,10 @@ public ScmProperties( String overriddenBranchName, Boolean overriddenIsClean, ScmIdentity identity, - Boolean unshallowRepoOnCI + Boolean unshallowRepoOnCI, + Set releaseBranchNames, + boolean releaseOnlyOnReleaseBranches, + boolean ignoreGlobalGitConfig ) { this.type = type; this.directory = directory; @@ -41,6 +48,9 @@ public ScmProperties( this.overriddenIsClean = overriddenIsClean; this.identity = identity; this.unshallowRepoOnCI = unshallowRepoOnCI; + this.releaseBranchNames = releaseBranchNames; + this.releaseOnlyOnReleaseBranches = releaseOnlyOnReleaseBranches; + this.ignoreGlobalGitConfig = ignoreGlobalGitConfig; } public ScmPushOptions pushOptions() { @@ -90,4 +100,16 @@ public final ScmIdentity getIdentity() { public Boolean isUnshallowRepoOnCI() { return unshallowRepoOnCI; } + + public Set getReleaseBranchNames() { + return releaseBranchNames; + } + + public boolean isReleaseOnlyOnReleaseBranches() { + return releaseOnlyOnReleaseBranches; + } + + public boolean isIgnoreGlobalGitConfig() { + return ignoreGlobalGitConfig; + } } diff --git a/src/main/java/pl/allegro/tech/build/axion/release/domain/scm/ScmService.java b/src/main/java/pl/allegro/tech/build/axion/release/domain/scm/ScmService.java index 9669af09..6db50e02 100644 --- a/src/main/java/pl/allegro/tech/build/axion/release/domain/scm/ScmService.java +++ b/src/main/java/pl/allegro/tech/build/axion/release/domain/scm/ScmService.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Optional; +import java.util.Set; public class ScmService { private static final Logger logger = Logging.getLogger(ScmService.class); @@ -69,4 +70,12 @@ public List lastLogMessages(int messageCount) { public boolean isLegacyDefTagnameRepo() { return repository.isLegacyDefTagnameRepo(); } + + public Set getReleaseBranchNames() { + return scmProperties.getReleaseBranchNames(); + } + + public boolean isReleaseOnlyOnReleaseBranches(){ + return scmProperties.isReleaseOnlyOnReleaseBranches(); + } } diff --git a/src/main/java/pl/allegro/tech/build/axion/release/infrastructure/git/GitRepository.java b/src/main/java/pl/allegro/tech/build/axion/release/infrastructure/git/GitRepository.java index f2029da1..f8d7c7fd 100644 --- a/src/main/java/pl/allegro/tech/build/axion/release/infrastructure/git/GitRepository.java +++ b/src/main/java/pl/allegro/tech/build/axion/release/infrastructure/git/GitRepository.java @@ -38,8 +38,7 @@ public class GitRepository implements ScmRepository { private final ScmProperties properties; public GitRepository(ScmProperties properties) { - SystemReader.setInstance(new SystemReaderWithoutSystemConfig()); - + SystemReader.setInstance(new SystemReaderWithoutSystemConfig(properties.isIgnoreGlobalGitConfig())); try { this.repositoryDir = properties.getDirectory(); this.jgitRepository = Git.open(repositoryDir); diff --git a/src/main/java/pl/allegro/tech/build/axion/release/infrastructure/git/SystemReaderWithoutSystemConfig.java b/src/main/java/pl/allegro/tech/build/axion/release/infrastructure/git/SystemReaderWithoutSystemConfig.java index b0b93f00..640d55e0 100644 --- a/src/main/java/pl/allegro/tech/build/axion/release/infrastructure/git/SystemReaderWithoutSystemConfig.java +++ b/src/main/java/pl/allegro/tech/build/axion/release/infrastructure/git/SystemReaderWithoutSystemConfig.java @@ -5,43 +5,43 @@ import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.SystemReader; -public class SystemReaderWithoutSystemConfig extends SystemReader -{ +public class SystemReaderWithoutSystemConfig extends SystemReader { private static final SystemReader DefaultSystemReader = SystemReader.getInstance(); + private final boolean ignoreUserSettings; + + public SystemReaderWithoutSystemConfig(boolean ignoreUserSettings) { + super(); + this.ignoreUserSettings = ignoreUserSettings; + } @Override - public String getenv(String variable) - { + public String getenv(String variable) { return DefaultSystemReader.getenv(variable); } @Override - public String getHostname() - { + public String getHostname() { return DefaultSystemReader.getHostname(); } @Override - public String getProperty(String key) - { + public String getProperty(String key) { return DefaultSystemReader.getProperty(key); } @Override - public long getCurrentTime() - { + public long getCurrentTime() { return DefaultSystemReader.getCurrentTime(); } @Override - public int getTimezone(long when) - { + public int getTimezone(long when) { return DefaultSystemReader.getTimezone(when); } @Override - public FileBasedConfig openUserConfig(Config parent, FS fs) - { + public FileBasedConfig openUserConfig(Config parent, FS fs) { + if (ignoreUserSettings) return new EmptyFileBasedConfig(parent, fs); return DefaultSystemReader.openUserConfig(parent, fs); } @@ -54,20 +54,22 @@ public FileBasedConfig openJGitConfig(Config parent, FS fs) { // This resolves issues with Gradle being unable to save configuration cache // Based on https://stackoverflow.com/a/59110721 @Override - public FileBasedConfig openSystemConfig(Config parent, FS fs) - { - return new FileBasedConfig(parent, null, fs) - { - @Override - public void load() - { - } + public FileBasedConfig openSystemConfig(Config parent, FS fs) { + return new EmptyFileBasedConfig(parent, fs); + } + + private static class EmptyFileBasedConfig extends FileBasedConfig { + public EmptyFileBasedConfig(Config parent, FS fs) { + super(parent, null, fs); + } + + @Override + public void load() { + } - @Override - public boolean isOutdated() - { - return false; - } - }; + @Override + public boolean isOutdated() { + return false; + } } } diff --git a/src/test/groovy/pl/allegro/tech/build/axion/release/RepositoryBasedTest.groovy b/src/test/groovy/pl/allegro/tech/build/axion/release/RepositoryBasedTest.groovy index c06f2cb2..d6d120a6 100644 --- a/src/test/groovy/pl/allegro/tech/build/axion/release/RepositoryBasedTest.groovy +++ b/src/test/groovy/pl/allegro/tech/build/axion/release/RepositoryBasedTest.groovy @@ -5,8 +5,8 @@ import pl.allegro.tech.build.axion.release.domain.LocalOnlyResolver import pl.allegro.tech.build.axion.release.domain.properties.PropertiesBuilder import pl.allegro.tech.build.axion.release.domain.scm.ScmProperties import pl.allegro.tech.build.axion.release.domain.scm.ScmRepository -import pl.allegro.tech.build.axion.release.infrastructure.di.VersionResolutionContext import pl.allegro.tech.build.axion.release.infrastructure.di.ScmRepositoryFactory +import pl.allegro.tech.build.axion.release.infrastructure.di.VersionResolutionContext import spock.lang.Specification import spock.lang.TempDir @@ -27,18 +27,15 @@ class RepositoryBasedTest extends Specification { def rawRepository = Grgit.init(dir: temporaryFolder) defaultBranch = rawRepository.branch.current().name - // let's make sure, not to use system wide user settings in tests - rawRepository.repository.jgit.repository.config.baseConfig.clear() - ScmProperties scmProperties = scmProperties(temporaryFolder).build() ScmRepository scmRepository = ScmRepositoryFactory.create(scmProperties) context = new VersionResolutionContext( - PropertiesBuilder.properties().build(), - scmRepository, - scmProperties, - temporaryFolder, - new LocalOnlyResolver(true) + PropertiesBuilder.properties().build(), + scmRepository, + scmProperties, + temporaryFolder, + new LocalOnlyResolver(true) ) repository = context.repository() @@ -47,9 +44,9 @@ class RepositoryBasedTest extends Specification { protected String currentVersion() { return context.versionService().currentDecoratedVersion( - context.rules().version, - context.rules().tag, - context.rules().nextVersion + context.rules().version, + context.rules().tag, + context.rules().nextVersion ).decoratedVersion } } diff --git a/src/test/groovy/pl/allegro/tech/build/axion/release/domain/ReleaserTest.groovy b/src/test/groovy/pl/allegro/tech/build/axion/release/domain/ReleaserTest.groovy index 62fefb86..a14572e1 100644 --- a/src/test/groovy/pl/allegro/tech/build/axion/release/domain/ReleaserTest.groovy +++ b/src/test/groovy/pl/allegro/tech/build/axion/release/domain/ReleaserTest.groovy @@ -1,12 +1,12 @@ package pl.allegro.tech.build.axion.release.domain +import pl.allegro.tech.build.axion.release.ReleaseBranchesConfiguration import pl.allegro.tech.build.axion.release.RepositoryBasedTest -import pl.allegro.tech.build.axion.release.TagPrefixConf import pl.allegro.tech.build.axion.release.domain.hooks.ReleaseHooksRunner import pl.allegro.tech.build.axion.release.domain.properties.Properties import pl.allegro.tech.build.axion.release.domain.scm.ScmService -import static pl.allegro.tech.build.axion.release.TagPrefixConf.* +import static pl.allegro.tech.build.axion.release.TagPrefixConf.fullPrefix import static pl.allegro.tech.build.axion.release.domain.properties.HooksPropertiesBuilder.hooksProperties import static pl.allegro.tech.build.axion.release.domain.properties.PropertiesBuilder.properties import static pl.allegro.tech.build.axion.release.domain.properties.VersionPropertiesBuilder.versionProperties @@ -25,12 +25,12 @@ class ReleaserTest extends RepositoryBasedTest { def "should release new version when not on tag"() { given: Properties rules = properties() - .withVersionRules(versionProperties().forceVersion('2.0.0').build()) - .withHooksRules(hooksProperties().withCommitHook().build()) - .build() + .withVersionRules(versionProperties().forceVersion('2.0.0').build()) + .withHooksRules(hooksProperties().withCommitHook().build()) + .build() when: - releaser.release(rules) + releaser.release(rules, new ReleaseBranchesConfiguration(false, 'main', ['main'] as Set)) then: currentVersion() == '2.0.0' @@ -41,7 +41,7 @@ class ReleaserTest extends RepositoryBasedTest { repository.tag(fullPrefix() + '1.0.0') when: - releaser.release(context.rules()) + releaser.release(context.rules(), new ReleaseBranchesConfiguration(false, 'main', ['main'] as Set)) then: currentVersion() == '1.0.0' @@ -50,12 +50,12 @@ class ReleaserTest extends RepositoryBasedTest { def "should release with forced pre-released versions"() { given: Properties rules = properties() - .withVersionRules(versionProperties().forceVersion('3.0.0-rc4').build()) - .withHooksRules(hooksProperties().withCommitHook().build()) - .build() + .withVersionRules(versionProperties().forceVersion('3.0.0-rc4').build()) + .withHooksRules(hooksProperties().withCommitHook().build()) + .build() when: - releaser.release(rules) + releaser.release(rules, new ReleaseBranchesConfiguration(false, 'main', ['main'] as Set)) then: currentVersion() == '3.0.0-rc4' @@ -66,7 +66,7 @@ class ReleaserTest extends RepositoryBasedTest { repository.tag(fullPrefix() + '3.0.0-rc4') when: - releaser.release(context.rules()) + releaser.release(context.rules(), new ReleaseBranchesConfiguration(false, 'main', ['main'] as Set)) then: currentVersion() == '3.0.0-rc4' @@ -74,11 +74,11 @@ class ReleaserTest extends RepositoryBasedTest { def "should increment pre-released version correctly"() { given: - repository.tag(fullPrefix() +'3.0.0-rc4') + repository.tag(fullPrefix() + '3.0.0-rc4') repository.commit(['*'], 'make is snapshot') when: - releaser.release(context.rules()) + releaser.release(context.rules(), new ReleaseBranchesConfiguration(false, 'main', ['main'] as Set)) then: currentVersion() == '3.0.1' @@ -87,12 +87,12 @@ class ReleaserTest extends RepositoryBasedTest { def "should create release commit if configured"() { given: Properties rules = properties() - .withVersionRules(versionProperties().forceVersion('3.0.0').build()) - .withHooksRules(hooksProperties().withCommitHook().build()) - .build() + .withVersionRules(versionProperties().forceVersion('3.0.0').build()) + .withHooksRules(hooksProperties().withCommitHook().build()) + .build() when: - releaser.release(rules) + releaser.release(rules, new ReleaseBranchesConfiguration(false, 'main', ['main'] as Set)) then: currentVersion() == '3.0.0' @@ -101,17 +101,46 @@ class ReleaserTest extends RepositoryBasedTest { def "should create release commit when on tag but forced"() { given: - repository.tag(fullPrefix() +'3.1.0') + repository.tag(fullPrefix() + '3.1.0') Properties rules = properties() - .withVersionRules(versionProperties().forceVersion('3.2.0').build()) - .withHooksRules(hooksProperties().withCommitHook().build()) - .build() + .withVersionRules(versionProperties().forceVersion('3.2.0').build()) + .withHooksRules(hooksProperties().withCommitHook().build()) + .build() when: - releaser.release(rules) + releaser.release(rules, new ReleaseBranchesConfiguration(false, 'main', ['main'] as Set)) then: currentVersion() == '3.2.0' repository.lastLogMessages(1) == ['release version: 3.2.0'] } + + def "should do release when isReleaseOnlyOnDefaultBranches option is set and current branch is in releaseBranchNames list"() { + given: + repository.tag(fullPrefix() + '1.0.0') + Properties rules = properties() + .withVersionRules(versionProperties().forceVersion('1.0.1').build()) + .withHooksRules(hooksProperties().withCommitHook().build()) + .build() + + when: + releaser.release(rules, new ReleaseBranchesConfiguration(true, 'main', ['main'] as Set)) + + then: + currentVersion() == '1.0.1' + } + + def "should skip release when current branch is not in releaseBranchNames list"() { + given: + repository.tag(fullPrefix() + '1.0.0') + Properties rules = properties() + .withHooksRules(hooksProperties().withCommitHook().build()) + .build() + + when: + releaser.release(rules, new ReleaseBranchesConfiguration(true, 'feature/branch', ['main'] as Set)) + + then: + currentVersion() == '1.0.0' + } } diff --git a/src/test/groovy/pl/allegro/tech/build/axion/release/domain/scm/ScmPropertiesBuilder.groovy b/src/test/groovy/pl/allegro/tech/build/axion/release/domain/scm/ScmPropertiesBuilder.groovy index 50ab51ca..3e496d6b 100644 --- a/src/test/groovy/pl/allegro/tech/build/axion/release/domain/scm/ScmPropertiesBuilder.groovy +++ b/src/test/groovy/pl/allegro/tech/build/axion/release/domain/scm/ScmPropertiesBuilder.groovy @@ -38,7 +38,10 @@ class ScmPropertiesBuilder { overriddenBranchName, overriddenIsClean, ScmIdentity.defaultIdentityWithoutAgents(), - true + true, + ['main', 'master'] as Set, + false, + true ) } diff --git a/src/test/groovy/pl/allegro/tech/build/axion/release/infrastructure/git/GitRepositoryTest.groovy b/src/test/groovy/pl/allegro/tech/build/axion/release/infrastructure/git/GitRepositoryTest.groovy index 2b5e7b59..4ace9175 100644 --- a/src/test/groovy/pl/allegro/tech/build/axion/release/infrastructure/git/GitRepositoryTest.groovy +++ b/src/test/groovy/pl/allegro/tech/build/axion/release/infrastructure/git/GitRepositoryTest.groovy @@ -9,13 +9,7 @@ import org.eclipse.jgit.lib.Constants import org.eclipse.jgit.transport.RemoteConfig import org.eclipse.jgit.transport.URIish import org.gradle.testfixtures.ProjectBuilder -import pl.allegro.tech.build.axion.release.domain.scm.ScmException -import pl.allegro.tech.build.axion.release.domain.scm.ScmIdentity -import pl.allegro.tech.build.axion.release.domain.scm.ScmPosition -import pl.allegro.tech.build.axion.release.domain.scm.ScmProperties -import pl.allegro.tech.build.axion.release.domain.scm.ScmPushOptions -import pl.allegro.tech.build.axion.release.domain.scm.ScmRepositoryUnavailableException -import pl.allegro.tech.build.axion.release.domain.scm.TagsOnCommit +import pl.allegro.tech.build.axion.release.domain.scm.* import pl.allegro.tech.build.axion.release.util.WithEnvironment import spock.lang.Specification @@ -178,7 +172,7 @@ class GitRepositoryTest extends Specification { repository.tag(fullPrefix() + '1') repository.commit(['*'], "commit after " + fullPrefix() + "1") repository.tag(fullPrefix() + '2') - repository.commit(['*'], "commit after " + fullPrefix() +"2") + repository.commit(['*'], "commit after " + fullPrefix() + "2") rawRepository.checkout(branch: fullPrefix() + '1') repository.commit(['*'], "bugfix after " + fullPrefix() + "1") @@ -193,9 +187,9 @@ class GitRepositoryTest extends Specification { def "should return all tagged commits matching the pattern provided"() { given: repository.tag(fullPrefix() + '1') - repository.commit(['*'], "commit after " + fullPrefix() +"1") + repository.commit(['*'], "commit after " + fullPrefix() + "1") repository.tag(fullPrefix() + '2') - repository.commit(['*'], "commit after " + fullPrefix() +"2") + repository.commit(['*'], "commit after " + fullPrefix() + "2") repository.tag('another-tag-1') repository.commit(['*'], "commit after another-tag-1") repository.commit(['*'], "commit after another-tag-1-2") @@ -208,13 +202,13 @@ class GitRepositoryTest extends Specification { List allTaggedCommits = repository.taggedCommits(List.of(compile('^' + defaultPrefix() + '.*'))) then: - allTaggedCommits.collect { c -> c.tags[0] } == [fullPrefix() +'3',fullPrefix() + '4', fullPrefix() + '2', fullPrefix() +'1'] + allTaggedCommits.collect { c -> c.tags[0] } == [fullPrefix() + '3', fullPrefix() + '4', fullPrefix() + '2', fullPrefix() + '1'] } def "should return only tags that match with prefix"() { given: repository.tag(fullPrefix() + '1') - repository.commit(['*'], "commit after " + fullPrefix() +"1") + repository.commit(['*'], "commit after " + fullPrefix() + "1") repository.tag('otherTag') when: @@ -338,12 +332,12 @@ class GitRepositoryTest extends Specification { where: expectedIsClean | overridenIsCleanFlag | dirtyRepository - false | false | false - true | true | false - false | false | true - true | true | true - true | null | false - false | null | true + false | false | false + true | true | false + false | false | true + true | true | true + true | null | false + false | null | true } def "should provide current branch name from overriddenBranchName when in detached state and overriddenBranchName is set"() { @@ -426,7 +420,7 @@ class GitRepositoryTest extends Specification { then: customRemoteRawRepository.log(maxCommits: 1)*.fullMessage == ['commit after ' + fullPrefix() + 'custom'] - customRemoteRawRepository.tag.list()*.fullName == ['refs/tags/' + fullPrefix() +'custom'] + customRemoteRawRepository.tag.list()*.fullName == ['refs/tags/' + fullPrefix() + 'custom'] remoteRawRepository.log(maxCommits: 1)*.fullMessage == ['InitialCommit'] remoteRawRepository.tag.list()*.fullName == [] } @@ -450,11 +444,11 @@ class GitRepositoryTest extends Specification { def "should remove tag"() { given: - repository.tag(fullPrefix() +"1") + repository.tag(fullPrefix() + "1") int intermediateSize = repository.taggedCommits(List.of(~/.*/)).size() when: - repository.dropTag(fullPrefix() +"1") + repository.dropTag(fullPrefix() + "1") then: intermediateSize == 1 @@ -514,7 +508,7 @@ class GitRepositoryTest extends Specification { isLegacyNamed } - def "existing legacy default tagname repo should return false on partially matches"() { + def "existing legacy default tagname repo should return false on partially matches"() { given: repository.tag("release-1") repository.tag("bla1") @@ -680,17 +674,17 @@ class GitRepositoryTest extends Specification { ]) def 'should not unshallow repo locally'() { given: - remoteRepository.tag(fullPrefix() + '1') - 100.times { remoteRepository.commit(['*'], "commit after release") } - File repoDir = File.createTempDir('axion-release', 'tmp') - Map repositories = GitProjectBuilder.gitProject(repoDir, remoteRepositoryDir, 1).build() - GitRepository repository = repositories[GitRepository] + remoteRepository.tag(fullPrefix() + '1') + 100.times { remoteRepository.commit(['*'], "commit after release") } + File repoDir = File.createTempDir('axion-release', 'tmp') + Map repositories = GitProjectBuilder.gitProject(repoDir, remoteRepositoryDir, 1).build() + GitRepository repository = repositories[GitRepository] when: - TagsOnCommit tags = repository.latestTags(List.of(compile('^' + defaultPrefix() + '.*'))) + TagsOnCommit tags = repository.latestTags(List.of(compile('^' + defaultPrefix() + '.*'))) then: - tags.tags.isEmpty() + tags.tags.isEmpty() } private void commitFile(String subDir, String fileName) {