Skip to content
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

DRAFT: feat(provider): add new maven provider for handling versions from pom.xml #963

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions commitizen/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
def is_rust_cargo(self) -> bool:
return os.path.isfile("Cargo.toml")

@property
def is_maven_project(self) -> bool:
return os.path.isfile("pom.xml")

@property
def is_npm_package(self) -> bool:
return os.path.isfile("package.json")
Expand Down Expand Up @@ -222,6 +226,7 @@
"commitizen": "commitizen: Fetch and set version in commitizen config (default)",
"cargo": "cargo: Get and set version from Cargo.toml:project.version field",
"composer": "composer: Get and set version from composer.json:project.version field",
"mvn": "mvn: Get and set version from pom.xml:project.version field",
"npm": "npm: Get and set version from package.json:project.version field",
"pep621": "pep621: Get and set version from pyproject.toml:project.version field",
"poetry": "poetry: Get and set version from pyproject.toml:tool.poetry.version field",
Expand All @@ -236,6 +241,8 @@
default_val = "pep621"
elif self.project_info.is_rust_cargo:
default_val = "cargo"
elif self.project_info.is_maven_project:
default_val = "mvn"

Check warning on line 245 in commitizen/commands/init.py

View check run for this annotation

Codecov / codecov/patch

commitizen/commands/init.py#L245

Added line #L245 was not covered by tests
elif self.project_info.is_npm_package:
default_val = "npm"
elif self.project_info.is_php_composer:
Expand Down
2 changes: 2 additions & 0 deletions commitizen/providers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from commitizen.providers.cargo_provider import CargoProvider
from commitizen.providers.commitizen_provider import CommitizenProvider
from commitizen.providers.composer_provider import ComposerProvider
from commitizen.providers.mvn_provider import MavenProvider
from commitizen.providers.npm_provider import NpmProvider
from commitizen.providers.pep621_provider import Pep621Provider
from commitizen.providers.poetry_provider import PoetryProvider
Expand All @@ -21,6 +22,7 @@
"CargoProvider",
"CommitizenProvider",
"ComposerProvider",
"MavenProvider",
"NpmProvider",
"Pep621Provider",
"PoetryProvider",
Expand Down
53 changes: 53 additions & 0 deletions commitizen/providers/mvn_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from __future__ import annotations

import subprocess

from commitizen.providers.base_provider import VersionProvider


class MavenProvider(VersionProvider):
"""
Maven version management

ref: https://octopus.com/blog/maven-versioning-explained

Major.Minor.Patch-BuildNumber-Qualifier

Precedence:
- alpha or a
- beta or b
- milestone or m
- rc or cr
- snapshot
- (the empty string) or ga or final or release
- sp
"""

FULL_VERSION_REGEX = r"(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)[\.-]?(?P<buildnumber>\d+)?[\.-]?(?P<qualifier>\w+)?"

TAG_FORMAT_REGEXS = {
"$version": r"(?P<version>.+)",
"$major": r"(?P<major>\d+)",
"$minor": r"(?P<minor>\d+)",
"$patch": r"(?P<patch>\d+)",
"$buildnumber": r"(?P<buildnumber>\d+)?",
"$qualifier": r"(?P<qualifier>\w+)?",
}

filename = "./pom.xml"

def __run_cmd(self, cmd) -> str:
return (
subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
.stdout.read() # type: ignore
.decode("utf-8")
.strip()
)

def get_version(self, file: str = filename) -> str:
return self.__run_cmd(
f"mvn help:evaluate -Dexpression=project.version -q -DforceStdout -f {file}"
)

def set_version(self, version: str, file: str = filename) -> None:
self.__run_cmd(f"mvn versions:set -DnewVersion={version} -f {file}")
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ restructuredtext = "commitizen.changelog_formats.restructuredtext:RestructuredTe
cargo = "commitizen.providers:CargoProvider"
commitizen = "commitizen.providers:CommitizenProvider"
composer = "commitizen.providers:ComposerProvider"
mvn = "commitizen.providers:MavenProvider"
npm = "commitizen.providers:NpmProvider"
pep621 = "commitizen.providers:Pep621Provider"
poetry = "commitizen.providers:PoetryProvider"
Expand Down
69 changes: 69 additions & 0 deletions tests/data/sample_pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<!-- PARENT -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath />
</parent>

<!-- BASICS -->
<groupId>io.github.commitizen-tools</groupId>
<artifactId>sample-maven-pom</artifactId>
<version>3.2.1</version>
<packaging>pom</packaging>

<!-- DESCRIPTION -->
<name>Sample Maven POM</name>
<description>This is a sample POM</description>

<scm>
<url>${app.url}</url>
<tag>v@{project.version}</tag>
</scm>

<!-- PROPS / VERSIONS -->
<properties>
<!-- App -->
<app.url>hthttps://github.com/commitizen-tools/commitizen</app.url>

<!-- Java -->
<java.version>17</java.version>

<!-- Spring -->
<spring-boot.version>3.1.0</spring-boot.version>
</properties>

<!-- BOM DEPS -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>${spring-boot.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

</project>
69 changes: 69 additions & 0 deletions tests/data/sample_pom_snapshot.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<!-- PARENT -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath />
</parent>

<!-- BASICS -->
<groupId>io.github.commitizen-tools</groupId>
<artifactId>sample-maven-pom</artifactId>
<version>3.2.1-SNAPSHOT</version>
<packaging>pom</packaging>

<!-- DESCRIPTION -->
<name>Sample Maven POM</name>
<description>This is a sample POM</description>

<scm>
<url>${app.url}</url>
<tag>v@{project.version}</tag>
</scm>

<!-- PROPS / VERSIONS -->
<properties>
<!-- App -->
<app.url>hthttps://github.com/commitizen-tools/commitizen</app.url>

<!-- Java -->
<java.version>17</java.version>

<!-- Spring -->
<spring-boot.version>3.1.0</spring-boot.version>
</properties>

<!-- BOM DEPS -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>${spring-boot.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

</project>
50 changes: 50 additions & 0 deletions tests/providers/test_mvn_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from __future__ import annotations

import pytest

import os

from commitizen.config.base_config import BaseConfig
from commitizen.providers.mvn_provider import MavenProvider


def test_can_run_subcommand(config: BaseConfig):
provider = MavenProvider(config)
got = provider._MavenProvider__run_cmd("echo 'hi'") # type: ignore
expected = "hi"
assert got == expected


@pytest.mark.parametrize(
"file, expected",
(
("./tests/data/sample_pom.xml", "3.2.1"),
("./tests/data/sample_pom_snapshot.xml", "3.2.1-SNAPSHOT"),
),
)
def test_get_version(config: BaseConfig, file: str, expected: str):
provider = MavenProvider(config)
got = provider.get_version(file)
assert got == expected


def test_set_version(config: BaseConfig):
provider = MavenProvider(config)
file = "./tests/data/sample_pom.xml"
expected = "3.2.2"
provider.set_version(expected, file)
got = provider.get_version(file)
assert got == expected

# rollback changes
expected = "3.2.1"
provider.set_version(expected, file)
got = provider.get_version(file)
assert got == expected

# delete backup file created
backup_file = file + ".versionsBackup"
assert os.path.exists(backup_file)
if os.path.exists(backup_file):
os.remove(backup_file)
assert not os.path.exists(backup_file)
Loading