Skip to content

Commit

Permalink
Support hatch version --force when downgrading with an explicit ver…
Browse files Browse the repository at this point in the history
…sion number

Closes: #1458
  • Loading branch information
warsaw committed Jul 27, 2024
1 parent 3adae6c commit 1dac31c
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 11 deletions.
4 changes: 3 additions & 1 deletion backend/src/hatchling/cli/version/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ def version_impl(
*,
called_by_app: bool, # noqa: ARG001
desired_version: str,
force: bool = False,
) -> None:
import os

Expand Down Expand Up @@ -37,7 +38,7 @@ def version_impl(
app.display(original_version)
return

updated_version = metadata.hatch.version.scheme.update(desired_version, original_version, version_data)
updated_version = metadata.hatch.version.scheme.update(desired_version, original_version, version_data, force)
source.set_version(updated_version, version_data)

app.display_info(f'Old: {original_version}')
Expand All @@ -48,4 +49,5 @@ def version_command(subparsers: argparse._SubParsersAction, defaults: Any) -> No
parser = subparsers.add_parser('version')
parser.add_argument('desired_version', default='', nargs='?', **defaults)
parser.add_argument('--app', dest='called_by_app', action='store_true', help=argparse.SUPPRESS)
parser.add_argument('--force', dest='force', action='store_true', help=argparse.SUPPRESS)
parser.set_defaults(func=version_impl)
2 changes: 1 addition & 1 deletion backend/src/hatchling/version/scheme/plugin/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def config(self) -> dict:
return self.__config

@abstractmethod
def update(self, desired_version: str, original_version: str, version_data: dict) -> str:
def update(self, desired_version: str, original_version: str, version_data: dict, *, force: bool = False) -> str:
"""
This should return a normalized form of the desired version and verify that it
is higher than the original version.
Expand Down
8 changes: 7 additions & 1 deletion backend/src/hatchling/version/scheme/standard.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ def update(
desired_version: str,
original_version: str,
version_data: dict, # noqa: ARG002
*,
force: bool = False,
) -> str:
from packaging.version import Version

Expand Down Expand Up @@ -57,7 +59,11 @@ def update(
raise ValueError(message)

next_version = Version(version)
if self.config.get('validate-bump', True) and next_version <= original:
if next_version <= original and not force and self.config.get('validate-bump', True):
# `hatch version --force` takes precedence and allows a
# downgrade. There is no --no-force option. If --force
# is not given, then consult the `validate-bump`
# configuration option.
message = f'Version `{version}` is not higher than the original version `{original_version}`'
raise ValueError(message)

Expand Down
14 changes: 7 additions & 7 deletions docs/community/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,41 @@ Clone the `hatch` repository, `cd` into it, and create a new branch for your con

```bash
cd hatch
git checkout -b add-my-contribution
git switch -c add-my-contribution
```

## Run the tests

Run the test suite while developing:

```bash
hatch run dev
hatch test
```

Run the test suite with coverage report:

```bash
hatch run cov
hatch test --cover
```

Run the extended test suite with coverage:

```bash
hatch run full
hatch test --cover --all
```

## Lint

Run automated formatting:

```bash
hatch run lint:fmt
hatch fmt --formatter
```

Run full linting and type checking:

```bash
hatch run lint:all
hatch fmt
```

## Docs
Expand All @@ -64,4 +64,4 @@ Build and validate the documentation website:

```bash
hatch run docs:build-check
```
```
1 change: 1 addition & 0 deletions docs/history/hatch.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
***Added:***

- The `version` and `project metadata` commands now support projects that do not use Hatchling as the build backend
- The `version` command accepts a `--force` option, allowing for downgrades when an explicit version number is given.
- Build environments can now be configured, the default build environment is `hatch-build`
- The environment interface now has the following methods and properties in order to better support builds on remote machines: `project_root`, `sep`, `pathsep`, `fs_context`

Expand Down
12 changes: 11 additions & 1 deletion src/hatch/cli/version/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,16 @@

@click.command(short_help="View or set a project's version")
@click.argument('desired_version', required=False)
@click.option(
'--force',
'-f',
is_flag=True,
default=False,
show_default=True,
help='Allow an explicit downgrading version to be given',
)
@click.pass_obj
def version(app: Application, desired_version: str | None):
def version(app: Application, desired_version: str | None, *, force: bool):
"""View or set a project's version."""
if app.project.root is None:
if app.project.chosen_name is None:
Expand Down Expand Up @@ -65,6 +73,8 @@ def version(app: Application, desired_version: str | None):

command = ['python', '-u', '-m', 'hatchling', 'version']
if desired_version:
if force:
command.append('--force')
command.append(desired_version)

context = ExecutionContext(app.project.build_env)
Expand Down
5 changes: 5 additions & 0 deletions tests/backend/version/scheme/test_standard.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ def test_not_higher(isolation):
scheme.update('1.0.0', '1.0', {})


def test_not_higher_with_force(isolation):
scheme = StandardScheme(str(isolation), {})
assert scheme.update('1.9.0', '2.0.0', {}, force=True) == '1.9.0'


def test_specific(isolation):
scheme = StandardScheme(str(isolation), {})

Expand Down
45 changes: 45 additions & 0 deletions tests/cli/version/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,51 @@ def test_set_dynamic(hatch, helpers, temp_dir):
)


@pytest.mark.usefixtures('mock_backend_process')
def test_set_dynamic_downgrade(hatch, helpers, temp_dir):
project_name = 'My.App'

with temp_dir.as_cwd():
hatch('new', project_name)

path = temp_dir / 'my-app'
data_path = temp_dir / 'data'
data_path.mkdir()

(path / 'src' / 'my_app' / '__about__.py').write_text('__version__ = "21.1.2"')

# This one fails, because it's a downgrade without --force
with path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch('version', '21.1.0', catch_exceptions=True)

assert result.exit_code == 1, result.output
assert str(result.exception) == 'Version `21.1.0` is not higher than the original version `21.1.2`'

# Try again, this time with --force
with path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch('version', '--force', '21.1.0')

assert result.exit_code == 0, result.output
assert result.output == helpers.dedent(
"""
Inspecting build dependencies
Old: 21.1.2
New: 21.1.0
"""
)

with path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
result = hatch('version')

assert result.exit_code == 0, result.output
assert result.output == helpers.dedent(
"""
Inspecting build dependencies
21.1.0
"""
)


def test_show_static(hatch, temp_dir):
project_name = 'My.App'

Expand Down

0 comments on commit 1dac31c

Please sign in to comment.