diff --git a/habushu-maven-plugin/pom.xml b/habushu-maven-plugin/pom.xml index dfe076b..a120221 100644 --- a/habushu-maven-plugin/pom.xml +++ b/habushu-maven-plugin/pom.xml @@ -89,6 +89,11 @@ maven-deploy-plugin ${version.maven.deploy.plugin} + + org.technologybrewery.baton + baton-maven-plugin + 0.1.0 + org.codehaus.plexus plexus-sec-dispatcher diff --git a/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/InstallDependenciesMojo.java b/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/InstallDependenciesMojo.java index 2522162..b738e76 100644 --- a/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/InstallDependenciesMojo.java +++ b/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/InstallDependenciesMojo.java @@ -15,6 +15,8 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.technologybrewery.habushu.exec.PoetryCommandHelper; +import org.technologybrewery.habushu.util.TomlReplacementTuple; +import org.technologybrewery.habushu.util.TomlUtils; import java.io.BufferedReader; import java.io.File; @@ -286,7 +288,7 @@ private void executeDetailedManagedDependencyMismatchActions(Map extras = config.get("extras"); - if (CollectionUtils.isNotEmpty(extras)) { - sb.append(", extras = ["); - // NB: if we expect more complex values, such as multiple extras, more work would need to be done for - // both consistent formatting and comparison of these values. However, at the time of initially writing - // this method, there isn't a clear demand signal, so we are going to KISS for now: - - for (int i = 0; i < extras.size(); i++) { - if (i > 0) { - sb.append(", "); - } - sb.append("\"").append(extras.get(i)).append("\""); - } - sb.append("]"); - } - sb.append("}"); - - return sb.toString(); - } - protected static String replaceSnapshotWithWildcard(String pomVersion) { return pomVersion.substring(0, pomVersion.indexOf(SNAPSHOT)) + ".*"; } @@ -492,31 +441,4 @@ protected static String replaceSnapshotWithDev(String pomVersion) { return pomVersion.substring(0, pomVersion.indexOf(SNAPSHOT)) + ".dev"; } - private class TomlReplacementTuple { - private String packageName; - - private String originalOperatorAndVersion; - - private String updatedOperatorAndVersion; - - public TomlReplacementTuple(String packageName, String originalOperatorAndVersion, String updatedOperatorAndVersion) { - this.packageName = packageName; - this.originalOperatorAndVersion = originalOperatorAndVersion; - this.updatedOperatorAndVersion = updatedOperatorAndVersion; - - } - - public String getPackageName() { - return packageName; - } - - public String getOriginalOperatorAndVersion() { - return originalOperatorAndVersion; - } - - public String getUpdatedOperatorAndVersion() { - return updatedOperatorAndVersion; - } - } - } diff --git a/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/MigrateMojo.java b/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/MigrateMojo.java new file mode 100644 index 0000000..d4a17e1 --- /dev/null +++ b/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/MigrateMojo.java @@ -0,0 +1,13 @@ +package org.technologybrewery.habushu; + +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.technologybrewery.baton.BatonMojo; + +/** + * Overriding the baton-maven-plugin so we can get access to Habushu's classpath for migration configuration. + */ +@Mojo(name = "baton-migrate", defaultPhase = LifecyclePhase.VALIDATE, requiresDependencyResolution = ResolutionScope.COMPILE, threadSafe = true) +public class MigrateMojo extends BatonMojo { +} diff --git a/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/migration/CustomMonorepoGroupMigration.java b/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/migration/CustomMonorepoGroupMigration.java new file mode 100644 index 0000000..6fe577d --- /dev/null +++ b/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/migration/CustomMonorepoGroupMigration.java @@ -0,0 +1,147 @@ +package org.technologybrewery.habushu.migration; + +import com.electronwill.nightconfig.core.CommentedConfig; +import com.electronwill.nightconfig.core.Config; +import com.electronwill.nightconfig.core.file.FileConfig; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.technologybrewery.baton.AbstractMigration; +import org.technologybrewery.baton.BatonException; +import org.technologybrewery.habushu.HabushuException; +import org.technologybrewery.habushu.util.TomlReplacementTuple; +import org.technologybrewery.habushu.util.TomlUtils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * Automatically migrates any monorepo dependencies (e.g., foo = {path = "../foo", develop = true}) in the main + * [tool.poetry.dependencies] group into the [tool.poetry.group.monorepo.dependencies] group instead. As noted in the + * project's README.md, this prevents these dependencies from causing issues when Poetry projects are exported in + * development releases. + */ +public class CustomMonorepoGroupMigration extends AbstractMigration { + + public static final Logger logger = LoggerFactory.getLogger(CustomMonorepoGroupMigration.class); + + protected Map replacements = new HashMap<>(); + + protected boolean hasExistingMonoRepoDependenciesGroup; + + @Override + protected boolean shouldExecuteOnFile(File file) { + replacements.clear(); + hasExistingMonoRepoDependenciesGroup = false; + + boolean shouldExecute = false; + try (FileConfig tomlFileConfig = FileConfig.of(file)) { + tomlFileConfig.load(); + + Optional toolPoetryDependencies = tomlFileConfig.getOptional(TomlUtils.TOOL_POETRY_DEPENDENCIES); + if (toolPoetryDependencies.isPresent()) { + Config foundDependencies = toolPoetryDependencies.get(); + Map dependencyMap = foundDependencies.valueMap(); + + for (Map.Entry dependency : dependencyMap.entrySet()) { + String packageName = dependency.getKey(); + Object packageRhs = dependency.getValue(); + if (TomlUtils.representsLocalDevelopmentVersion(packageRhs)) { + String packageRshAsString = TomlUtils.convertCommentedConfigToToml((CommentedConfig) packageRhs); + logger.info("Found local dependency not within monorepo group! ({} = {})", packageName, packageRshAsString); + TomlReplacementTuple replacementTuple = new TomlReplacementTuple(packageName, packageRshAsString, ""); + replacements.put(packageName, replacementTuple); + shouldExecute = true; + } + } + } + + Optional toolPoetryMonorepoDependencies = tomlFileConfig.getOptional(TomlUtils.TOOL_POETRY_GROUP_MONOREPO_DEPENDENCIES); + if (toolPoetryMonorepoDependencies.isPresent()) { + hasExistingMonoRepoDependenciesGroup = true; + } + } + + return shouldExecute; + } + + @Override + protected boolean performMigration(File pyProjectTomlFile) { + String fileContent = StringUtils.EMPTY; + try (BufferedReader reader = new BufferedReader(new FileReader(pyProjectTomlFile))) { + String line = reader.readLine(); + boolean injectAfterNextEmptyLine = false; + + while (line != null) { + boolean addLine = true; + boolean isEmptyLine = line.isBlank(); + + if (line.contains(StringUtils.SPACE) && line.contains(TomlUtils.EQUALS)) { + String key = line.substring(0, line.indexOf(StringUtils.SPACE)); + + if (key == null) { + key = line.substring(0, line.indexOf(TomlUtils.EQUALS)); + } + + if (key != null) { + key = key.strip(); + + TomlReplacementTuple matchedTuple = replacements.get(key); + if (matchedTuple != null) { + // skip this line, we will add it back to [tool.poetry.group.monorepo.dependencies] later + addLine = false; + } + } + + } else if (line.contains("[") && line.contains("]")) { + String key = line.strip(); + + if (hasExistingMonoRepoDependenciesGroup && (key.equals("[" + TomlUtils.TOOL_POETRY_GROUP_MONOREPO_DEPENDENCIES + "]"))) { + // skip this line as we are overriding with the line plus monorepo dependencies here: + addLine = false; + fileContent += line + "\n"; + fileContent = injectMonorepoDependencies(fileContent); + } else if (!hasExistingMonoRepoDependenciesGroup && (key.equals("[" + TomlUtils.TOOL_POETRY_DEPENDENCIES + "]"))) { + injectAfterNextEmptyLine = true; + } + } + + if (isEmptyLine && injectAfterNextEmptyLine) { + fileContent += "\n[" + TomlUtils.TOOL_POETRY_GROUP_MONOREPO_DEPENDENCIES + "]" + "\n"; + fileContent = injectMonorepoDependencies(fileContent); + injectAfterNextEmptyLine = false; + } + + if (addLine) { + fileContent += line + "\n"; + } + + line = reader.readLine(); + } + + } catch (IOException e) { + throw new HabushuException("Problem reading pyproject.toml to update with managed dependencies!", e); + } + + try { + TomlUtils.writeTomlFile(pyProjectTomlFile, fileContent); + } catch (IOException e) { + throw new BatonException("Problem moving monorepo dependencies to [tool.poetry.group.monorepo.dependencies]!", e); + } + + return true; + + } + + private String injectMonorepoDependencies(String fileContent) { + for (Map.Entry entry : replacements.entrySet()) { + fileContent += entry.getKey() + " = " + TomlUtils.escapeTomlRightHandSide(entry.getValue().getOriginalOperatorAndVersion()) + "\n"; + } + return fileContent; + } +} diff --git a/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/util/TomlReplacementTuple.java b/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/util/TomlReplacementTuple.java new file mode 100644 index 0000000..c50091c --- /dev/null +++ b/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/util/TomlReplacementTuple.java @@ -0,0 +1,28 @@ +package org.technologybrewery.habushu.util; + +public class TomlReplacementTuple { + private String packageName; + + private String originalOperatorAndVersion; + + private String updatedOperatorAndVersion; + + public TomlReplacementTuple(String packageName, String originalOperatorAndVersion, String updatedOperatorAndVersion) { + this.packageName = packageName; + this.originalOperatorAndVersion = originalOperatorAndVersion; + this.updatedOperatorAndVersion = updatedOperatorAndVersion; + + } + + public String getPackageName() { + return packageName; + } + + public String getOriginalOperatorAndVersion() { + return originalOperatorAndVersion; + } + + public String getUpdatedOperatorAndVersion() { + return updatedOperatorAndVersion; + } +} diff --git a/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/util/TomlUtils.java b/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/util/TomlUtils.java new file mode 100644 index 0000000..f43359d --- /dev/null +++ b/habushu-maven-plugin/src/main/java/org/technologybrewery/habushu/util/TomlUtils.java @@ -0,0 +1,110 @@ +package org.technologybrewery.habushu.util; + +import com.electronwill.nightconfig.core.CommentedConfig; +import org.apache.commons.collections4.CollectionUtils; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.List; + +/** + * Common utility methods for handling TOML files. + */ +public final class TomlUtils { + + public static final String EQUALS = "="; + public static final String DOUBLE_QUOTE = "\""; + public static final String TOOL_POETRY_DEPENDENCIES = "tool.poetry.dependencies"; + public static final String TOOL_POETRY_GROUP_MONOREPO_DEPENDENCIES = "tool.poetry.group.monorepo.dependencies"; + public static final String VERSION = "version"; + public static final String PATH = "path"; + public static final String DEVELOP = "develop"; + public static final String EXTRAS = "extras"; + + protected TomlUtils() { + // prevent instantiation of all static class + } + + public static boolean representsLocalDevelopmentVersion(Object rawData) { + boolean localDevelopmentVersion = false; + + if (rawData instanceof CommentedConfig) { + CommentedConfig config = (CommentedConfig) rawData; + if (!config.contains(VERSION)) { + localDevelopmentVersion = true; + } + + } + + return localDevelopmentVersion; + } + + /** + * Handles escaping with double quotes only if the value is not an inline table. + * + * @param valueToEscape value to potentially escape + * @return value ready to write to toml file + */ + public static String escapeTomlRightHandSide(String valueToEscape) { + return (!valueToEscape.contains("{")) ? DOUBLE_QUOTE + valueToEscape + DOUBLE_QUOTE : valueToEscape; + } + + public static void writeTomlFile(File pyProjectTomlFile, String fileContent) throws IOException { + if (fileContent != null) { + try (Writer writer = new FileWriter(pyProjectTomlFile)) { + writer.write(fileContent); + } + } + } + + public static String convertCommentedConfigToToml(CommentedConfig config) { + int valuesRemaining = config.size(); + + StringBuilder sb = new StringBuilder(); + sb.append("{"); + + if (config.get(PATH) != null) { + sb.append(PATH).append(" = \"").append(config.get(PATH).toString()).append("\""); + valuesRemaining--; + addCommaBetweenValues(valuesRemaining, sb); + } + + if (config.get(DEVELOP) != null) { + sb.append(DEVELOP).append(" = ").append(config.get(DEVELOP).toString()); + valuesRemaining--; + addCommaBetweenValues(valuesRemaining, sb); + } + + if (config.get(VERSION) != null) { + sb.append(VERSION).append(" = \"").append(config.get(VERSION).toString()).append("\""); + List extras = config.get(EXTRAS); + if (CollectionUtils.isNotEmpty(extras)) { + sb.append(", ").append(EXTRAS).append(" = ["); + // NB: if we expect more complex values, such as multiple extras, more work would need to be done for + // both consistent formatting and comparison of these values. However, at the time of initially writing + // this method, there isn't a clear demand signal, so we are going to KISS for now: + + for (int i = 0; i < extras.size(); i++) { + if (i > 0) { + sb.append(", "); + } + sb.append("\"").append(extras.get(i)).append("\""); + } + sb.append("]"); + } + } + + sb.append("}"); + + return sb.toString(); + } + + private static void addCommaBetweenValues(int valuesRemaining, StringBuilder sb) { + if (valuesRemaining > 0) { + sb.append(", "); + } + } + +} diff --git a/habushu-maven-plugin/src/main/resources/META-INF/plexus/components.xml b/habushu-maven-plugin/src/main/resources/META-INF/plexus/components.xml index b4a946e..8aec40d 100644 --- a/habushu-maven-plugin/src/main/resources/META-INF/plexus/components.xml +++ b/habushu-maven-plugin/src/main/resources/META-INF/plexus/components.xml @@ -13,8 +13,11 @@ default - org.technologybrewery.habushu:habushu-maven-plugin:${project.version}:validate-pyenv-and-poetry - org.technologybrewery.habushu:habushu-maven-plugin:${project.version}:initialize-habushu + + org.technologybrewery.habushu:habushu-maven-plugin:${project.version}:initialize-habushu, + org.technologybrewery.habushu:habushu-maven-plugin:${project.version}:validate-pyenv-and-poetry, + org.technologybrewery.habushu:habushu-maven-plugin:${project.version}:baton-migrate + org.technologybrewery.habushu:habushu-maven-plugin:${project.version}:install-dependencies org.technologybrewery.habushu:habushu-maven-plugin:${project.version}:format-python org.technologybrewery.habushu:habushu-maven-plugin:${project.version}:behave-bdd-test diff --git a/habushu-maven-plugin/src/main/resources/migrations.json b/habushu-maven-plugin/src/main/resources/migrations.json new file mode 100644 index 0000000..4371f69 --- /dev/null +++ b/habushu-maven-plugin/src/main/resources/migrations.json @@ -0,0 +1,11 @@ +[ + { + "name": "custom-monorepo-group-migration", + "implementation": "org.technologybrewery.habushu.migration.CustomMonorepoGroupMigration", + "fileSets": [ + { + "includes": ["pyproject.toml"] + } + ] + } +] \ No newline at end of file diff --git a/habushu-maven-plugin/src/test/java/org/technologybrewery/habushu/DependencyManagementSteps.java b/habushu-maven-plugin/src/test/java/org/technologybrewery/habushu/DependencyManagementSteps.java index 2d2d78e..b2c9856 100644 --- a/habushu-maven-plugin/src/test/java/org/technologybrewery/habushu/DependencyManagementSteps.java +++ b/habushu-maven-plugin/src/test/java/org/technologybrewery/habushu/DependencyManagementSteps.java @@ -6,7 +6,6 @@ import io.cucumber.java.en.When; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Assertions; import java.io.BufferedReader; diff --git a/habushu-maven-plugin/src/test/java/org/technologybrewery/habushu/migration/MonorepoMigrationSteps.java b/habushu-maven-plugin/src/test/java/org/technologybrewery/habushu/migration/MonorepoMigrationSteps.java new file mode 100644 index 0000000..4884002 --- /dev/null +++ b/habushu-maven-plugin/src/test/java/org/technologybrewery/habushu/migration/MonorepoMigrationSteps.java @@ -0,0 +1,112 @@ +package org.technologybrewery.habushu.migration; + +import com.electronwill.nightconfig.core.Config; +import com.electronwill.nightconfig.core.file.FileConfig; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import org.technologybrewery.habushu.util.TomlUtils; + +import java.io.File; +import java.util.Map; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class MonorepoMigrationSteps { + + private File testTomlFileDirectory = new File("./target/test-classes/migration/monorepo"); + private File pyProjectToml; + + private boolean shouldExecute; + + private boolean executionSucceeded; + + @Given("an existing pyproject.toml file with two monorepo dependencies in the tool.poetry.dependencies group") + public void an_existing_pyproject_toml_file_with_two_monorepo_dependencies_in_the_tool_poetry_dependencies_group() { + pyProjectToml = new File(testTomlFileDirectory, "with-dependencies-no-monorepo-group.toml"); + } + + @Given("an existing pyproject.toml file with two monorepo dependencies each in the tool.poetry.dependencies and tool.poetry.group.monorepo.dependencies groups") + public void an_existing_pyproject_toml_file_with_two_monorepo_dependencies_each_in_the_tool_poetry_dependencies_and_tool_poetry_group_monorepo_dependencies_groups() { + pyProjectToml = new File(testTomlFileDirectory, "with-dependencies-in-both-groups.toml"); + } + + @Given("an existing pyproject.toml without any monorepo dependencies") + public void an_existing_pyproject_toml_without_any_monorepo_dependencies() { + pyProjectToml = new File(testTomlFileDirectory, "no-monorepo-dependencies-present.toml"); + } + + + @Given("an existing pyproject.toml file with three monorepo dependencies already in the tool.poetry.group.monorepo.dependencies group") + public void an_existing_pyproject_toml_file_with_three_monorepo_dependencies_already_in_the_tool_poetry_group_monorepo_dependencies_group() { + pyProjectToml = new File(testTomlFileDirectory, "with-dependencies-already-in-monorepo-group.toml"); + } + + @When("Habushu migrations execute") + public void habushu_migrations_execute() { + CustomMonorepoGroupMigration migration = new CustomMonorepoGroupMigration(); + shouldExecute = migration.shouldExecuteOnFile(pyProjectToml); + executionSucceeded = (shouldExecute) ? migration.performMigration(pyProjectToml) : false; + } + + @Then("{int} pyproject.toml monorepo dependencies exist in the tool.poetry.group.monorepo.dependencies group") + public void pyproject_toml_monorepo_dependencies_exist_in_the_tool_poetry_group_monorepo_dependencies_group(Integer expectedMonorepoGroupDependencies) { + verifyExeuctionOccurred(); + try (FileConfig tomlFileConfig = FileConfig.of(pyProjectToml)) { + tomlFileConfig.load(); + + Optional toolPoetryMonorepoDependencies = tomlFileConfig.getOptional(TomlUtils.TOOL_POETRY_GROUP_MONOREPO_DEPENDENCIES); + int numberOfMonorepoDependenciesInMonorepoGroup = getNumberOfMonorepoChildren(toolPoetryMonorepoDependencies); + assertEquals(expectedMonorepoGroupDependencies, numberOfMonorepoDependenciesInMonorepoGroup, + expectedMonorepoGroupDependencies + " monorepo dependencies should exist in monorepo group!"); + + + } + } + @Then("{int} pyproject.toml monorepo dependencies exist in the tool.poetry.dependencies group") + public void pyproject_toml_monorepo_dependencies_exist_in_the_tool_poetry_dependencies_group(Integer expectedMainGroupDependencies) { + verifyExeuctionOccurred(); + try (FileConfig tomlFileConfig = FileConfig.of(pyProjectToml)) { + tomlFileConfig.load(); + + Optional toolPoetryDependencies = tomlFileConfig.getOptional(TomlUtils.TOOL_POETRY_DEPENDENCIES); + int numberOfMonorepoDependenciesInMainGroup = getNumberOfMonorepoChildren(toolPoetryDependencies); + assertEquals(expectedMainGroupDependencies, numberOfMonorepoDependenciesInMainGroup, + expectedMainGroupDependencies + " monorepo dependencies should remain in main group!"); + } + } + + @Then("no migration was performed") + public void no_migration_was_performed() { + assertFalse(shouldExecute, "Migration execution should have been skipped!"); + } + + + private static int getNumberOfMonorepoChildren(Optional tomlElement) { + int numberOfMonorepoDependencies = 0; + if (tomlElement.isPresent()) { + Config foundDependencies = tomlElement.get(); + Map dependencyMap = foundDependencies.valueMap(); + + for (Map.Entry dependency : dependencyMap.entrySet()) { + String packageName = dependency.getKey(); + Object packageRhs = dependency.getValue(); + if (TomlUtils.representsLocalDevelopmentVersion(packageRhs)) { + numberOfMonorepoDependencies++; + } + } + } + + return numberOfMonorepoDependencies; + } + + + private void verifyExeuctionOccurred() { + assertTrue(shouldExecute, "Migration should have been selected to execute!"); + assertTrue(executionSucceeded, "Migration should have executed successfully!"); + } + +} diff --git a/habushu-maven-plugin/src/test/resources/migration/monorepo/no-monorepo-dependencies-present.toml b/habushu-maven-plugin/src/test/resources/migration/monorepo/no-monorepo-dependencies-present.toml new file mode 100644 index 0000000..7ff8c7e --- /dev/null +++ b/habushu-maven-plugin/src/test/resources/migration/monorepo/no-monorepo-dependencies-present.toml @@ -0,0 +1,16 @@ +[tool.poetry] +name = "no-monorepo-dependencies-present" +version = "2.9.0.dev" +description = "Test monorepo migration does not impact toml file with no applicable changes" +authors = ["Test "] +license = "MIT License" + +[tool.poetry.dependencies] +python = "^3.11" + +[tool.poetry.dev-dependencies] +black = "^18.0.0" + +[build-system] +requires = ["poetry-core>=1.6.0"] +build-backend = "poetry.core.masonry.api" diff --git a/habushu-maven-plugin/src/test/resources/migration/monorepo/with-dependencies-already-in-monorepo-group.toml b/habushu-maven-plugin/src/test/resources/migration/monorepo/with-dependencies-already-in-monorepo-group.toml new file mode 100644 index 0000000..75ae26b --- /dev/null +++ b/habushu-maven-plugin/src/test/resources/migration/monorepo/with-dependencies-already-in-monorepo-group.toml @@ -0,0 +1,21 @@ +[tool.poetry] +name = "with-dependencies-already-in-monorepo-group" +version = "2.9.0.dev" +description = "Test moving monorepo dependecies when monorepo group already exists and no more chages are needed" +authors = ["Test "] +license = "MIT License" + +[tool.poetry.dependencies] +python = "^3.11" + +[tool.poetry.group.monorepo.dependencies] +some-local-monorepo-dependencies-1 = {path = "../some-local-monorepo-dependencies-1", develop = true} +some-local-monorepo-dependencies-2 = {path = "../some-local-monorepo-dependencies-2", develop = true} +some-local-monorepo-dependencies-3 = {path = "../some-local-monorepo-dependencies-3", develop = true} + +[tool.poetry.dev-dependencies] +black = "^18.0.0" + +[build-system] +requires = ["poetry-core>=1.6.0"] +build-backend = "poetry.core.masonry.api" diff --git a/habushu-maven-plugin/src/test/resources/migration/monorepo/with-dependencies-in-both-groups.toml b/habushu-maven-plugin/src/test/resources/migration/monorepo/with-dependencies-in-both-groups.toml new file mode 100644 index 0000000..2829763 --- /dev/null +++ b/habushu-maven-plugin/src/test/resources/migration/monorepo/with-dependencies-in-both-groups.toml @@ -0,0 +1,22 @@ +[tool.poetry] +name = "with-dependencies-is-both-groups" +version = "2.9.0.dev" +description = "Test moving monorepo dependecies from main to monorepo group when monorepo group already exists" +authors = ["Test "] +license = "MIT License" + +[tool.poetry.dependencies] +python = "^3.11" +some-local-monorepo-dependencies-1 = {path = "../some-local-monorepo-dependencies-1", develop = true} +some-local-monorepo-dependencies-2 = {path = "../some-local-monorepo-dependencies-2", develop = true} + +[tool.poetry.group.monorepo.dependencies] +some-local-monorepo-dependencies-3 = {path = "../some-local-monorepo-dependencies-3", develop = true} +some-local-monorepo-dependencies-4 = {path = "../some-local-monorepo-dependencies-4", develop = true} + +[tool.poetry.dev-dependencies] +black = "^18.0.0" + +[build-system] +requires = ["poetry-core>=1.6.0"] +build-backend = "poetry.core.masonry.api" diff --git a/habushu-maven-plugin/src/test/resources/migration/monorepo/with-dependencies-no-monorepo-group.toml b/habushu-maven-plugin/src/test/resources/migration/monorepo/with-dependencies-no-monorepo-group.toml new file mode 100644 index 0000000..dde98b2 --- /dev/null +++ b/habushu-maven-plugin/src/test/resources/migration/monorepo/with-dependencies-no-monorepo-group.toml @@ -0,0 +1,18 @@ +[tool.poetry] +name = "with-dependencies-no-monorepo-group" +version = "2.9.0.dev" +description = "Test moving monorepo dependecies from main to monorepo group" +authors = ["Test "] +license = "MIT License" + +[tool.poetry.dependencies] +python = "^3.11" +some-local-monorepo-dependencies-1 = {path = "../some-local-monorepo-dependencies-1", develop = true} +some-local-monorepo-dependencies-2 = {path = "../some-local-monorepo-dependencies-2", develop = true} + +[tool.poetry.dev-dependencies] +black = "^18.0.0" + +[build-system] +requires = ["poetry-core>=1.6.0"] +build-backend = "poetry.core.masonry.api" diff --git a/habushu-maven-plugin/src/test/resources/specifications/monorepo-migrations.feature b/habushu-maven-plugin/src/test/resources/specifications/monorepo-migrations.feature new file mode 100644 index 0000000..da4bf80 --- /dev/null +++ b/habushu-maven-plugin/src/test/resources/specifications/monorepo-migrations.feature @@ -0,0 +1,23 @@ +Feature: Test automatic migration of monorepo dependencies into their own pyproject.toml group + + Scenario: Migrate monorepo dependencies when existing monorepo group DOES NOT exists + Given an existing pyproject.toml file with two monorepo dependencies in the tool.poetry.dependencies group + When Habushu migrations execute + Then 2 pyproject.toml monorepo dependencies exist in the tool.poetry.group.monorepo.dependencies group + And 0 pyproject.toml monorepo dependencies exist in the tool.poetry.dependencies group + + Scenario: Migrate monorepo dependencies when existing monorepo group DOES exists + Given an existing pyproject.toml file with two monorepo dependencies each in the tool.poetry.dependencies and tool.poetry.group.monorepo.dependencies groups + When Habushu migrations execute + Then 4 pyproject.toml monorepo dependencies exist in the tool.poetry.group.monorepo.dependencies group + And 0 pyproject.toml monorepo dependencies exist in the tool.poetry.dependencies group + + Scenario: Migrate monorepo dependencies does not change a file with non applicable dependencies + Given an existing pyproject.toml without any monorepo dependencies + When Habushu migrations execute + Then no migration was performed + + Scenario: Migrate monorepo dependencies does not change a file with all monorepo dependencies already in monorepo group + Given an existing pyproject.toml file with three monorepo dependencies already in the tool.poetry.group.monorepo.dependencies group + When Habushu migrations execute + Then no migration was performed \ No newline at end of file