bumpy-cli 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daniel-Felipe-Santana-Batista
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,141 @@
1
+ Metadata-Version: 2.4
2
+ Name: bumpy-cli
3
+ Version: 0.1.0
4
+ Summary: CLI para gerenciar versoes de jobs em pipelines.
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Keywords: cli,pipeline,versionamento,jobs
8
+ Author: Daniel Felipe Santana Batista
9
+ Author-email: daniel.sbatista@shopee.com
10
+ Requires-Python: >=3.12
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Natural Language :: Portuguese (Brazilian)
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development
20
+ Classifier: Topic :: Utilities
21
+ Requires-Dist: typer (>=0.27.2,<0.28.0)
22
+ Project-URL: Documentation, https://bumpy-cli.readthedocs.io/pt-br/latest/
23
+ Project-URL: Homepage, https://github.com/iamDFSB/Bumpy-CLI
24
+ Project-URL: Repository, https://github.com/iamDFSB/Bumpy-CLI
25
+ Description-Content-Type: text/markdown
26
+
27
+ ![Bumpy CLI](docs/assets/images/logo.png)
28
+
29
+ # Bumpy CLI
30
+
31
+ [![Documentação](https://img.shields.io/badge/Documenta%C3%A7%C3%A3o-Read%20the%20Docs-blue?logo=readthedocs)](https://bumpy-cli.readthedocs.io/pt-br/latest/)
32
+ [![Codecov](https://codecov.io/gh/iamDFSB/Bumpy-CLI/branch/main/graph/badge.svg)](https://app.codecov.io/github/iamDFSB/Bumpy-CLI)
33
+ [![CI](https://github.com/iamDFSB/Bumpy-CLI/actions/workflows/pipeline.yaml/badge.svg)](https://github.com/iamDFSB/Bumpy-CLI/actions)
34
+
35
+ O Bumpy CLI ajuda a atualizar as versões dos jobs mantidos em arquivos `version`
36
+ de um pipeline. Com ele, você pode incrementar ou decrementar `major`, `minor`
37
+ ou `patch` de um job específico ou de todos os jobs de um ambiente.
38
+
39
+ ## Requisitos
40
+
41
+ - Python 3.12 ou superior;
42
+ - um projeto com a estrutura de pastas descrita abaixo.
43
+
44
+ ## Instalação
45
+
46
+ Como o Bumpy é uma ferramenta de linha de comando, recomendamos instalá-lo com
47
+ [pipx](https://pipx.pypa.io/), que mantem as dependencias isoladas:
48
+
49
+ ```bash
50
+ pipx install bumpy-cli
51
+ ```
52
+
53
+ Também é possível instalar no ambiente Python ativo:
54
+
55
+ ```bash
56
+ python -m pip install bumpy-cli
57
+ ```
58
+
59
+ Confirme a instalacao e veja os comandos disponiveis:
60
+
61
+ ```bash
62
+ bumpy --help
63
+ ```
64
+
65
+ ## Prepare o projeto
66
+
67
+ Execute os comandos a partir da raiz do projeto que contem a pasta `pipeline`.
68
+ Cada job precisa ter um arquivo `version` com tres numeros separados por ponto:
69
+
70
+ ```text
71
+ pipeline/
72
+ ├── prd-marketplace/
73
+ │ └── meu-cron/
74
+ │ └── version
75
+ └── uat/
76
+ └── meu-cron/
77
+ └── version
78
+ ```
79
+
80
+ Por exemplo, o arquivo `pipeline/prd-marketplace/meu-cron/version` pode conter:
81
+
82
+ ```text
83
+ 1.2.3
84
+ ```
85
+
86
+ ## Uso
87
+
88
+ ### Atualizar um job
89
+
90
+ Por padrão, os comandos atuam no ambiente `prd-marketplace`:
91
+
92
+ ```bash
93
+ bumpy job up meu-cron patch
94
+ ```
95
+
96
+ Esse comando altera `1.2.3` para `1.2.4`. Para atualizar outro segmento:
97
+
98
+ ```bash
99
+ bumpy job up meu-cron minor
100
+ bumpy job up meu-cron major
101
+ ```
102
+
103
+ Use `down` para decrementar o segmento. O valor não pode ficar abaixo de zero:
104
+
105
+ ```bash
106
+ bumpy job down meu-cron patch
107
+ ```
108
+
109
+ Para atuar no ambiente `uat`, adicione `--uat`:
110
+
111
+ ```bash
112
+ bumpy job up meu-cron patch --uat
113
+ ```
114
+
115
+ ### Atualizar todos os jobs de um ambiente
116
+
117
+ Os comandos `all` atualizam todos os jobs dentro do ambiente selecionado:
118
+
119
+ ```bash
120
+ bumpy all up patch
121
+ bumpy all down minor
122
+ bumpy all up major --uat
123
+ ```
124
+
125
+ Cada pasta de job do ambiente precisa conter um arquivo `version` válido.
126
+
127
+ ## Ajuda
128
+
129
+ Consulte a ajuda geral ou a de um grupo de comandos:
130
+
131
+ ```bash
132
+ bumpy --help
133
+ bumpy job --help
134
+ bumpy all --help
135
+ ```
136
+
137
+ ## Desenvolvimento
138
+
139
+ O código-fonte, as instruções para contribuir e a documentação do projeto estão
140
+ no [repositorio no GitHub](https://github.com/iamDFSB/Bumpy-CLI).
141
+
@@ -0,0 +1,114 @@
1
+ ![Bumpy CLI](docs/assets/images/logo.png)
2
+
3
+ # Bumpy CLI
4
+
5
+ [![Documentação](https://img.shields.io/badge/Documenta%C3%A7%C3%A3o-Read%20the%20Docs-blue?logo=readthedocs)](https://bumpy-cli.readthedocs.io/pt-br/latest/)
6
+ [![Codecov](https://codecov.io/gh/iamDFSB/Bumpy-CLI/branch/main/graph/badge.svg)](https://app.codecov.io/github/iamDFSB/Bumpy-CLI)
7
+ [![CI](https://github.com/iamDFSB/Bumpy-CLI/actions/workflows/pipeline.yaml/badge.svg)](https://github.com/iamDFSB/Bumpy-CLI/actions)
8
+
9
+ O Bumpy CLI ajuda a atualizar as versões dos jobs mantidos em arquivos `version`
10
+ de um pipeline. Com ele, você pode incrementar ou decrementar `major`, `minor`
11
+ ou `patch` de um job específico ou de todos os jobs de um ambiente.
12
+
13
+ ## Requisitos
14
+
15
+ - Python 3.12 ou superior;
16
+ - um projeto com a estrutura de pastas descrita abaixo.
17
+
18
+ ## Instalação
19
+
20
+ Como o Bumpy é uma ferramenta de linha de comando, recomendamos instalá-lo com
21
+ [pipx](https://pipx.pypa.io/), que mantem as dependencias isoladas:
22
+
23
+ ```bash
24
+ pipx install bumpy-cli
25
+ ```
26
+
27
+ Também é possível instalar no ambiente Python ativo:
28
+
29
+ ```bash
30
+ python -m pip install bumpy-cli
31
+ ```
32
+
33
+ Confirme a instalacao e veja os comandos disponiveis:
34
+
35
+ ```bash
36
+ bumpy --help
37
+ ```
38
+
39
+ ## Prepare o projeto
40
+
41
+ Execute os comandos a partir da raiz do projeto que contem a pasta `pipeline`.
42
+ Cada job precisa ter um arquivo `version` com tres numeros separados por ponto:
43
+
44
+ ```text
45
+ pipeline/
46
+ ├── prd-marketplace/
47
+ │ └── meu-cron/
48
+ │ └── version
49
+ └── uat/
50
+ └── meu-cron/
51
+ └── version
52
+ ```
53
+
54
+ Por exemplo, o arquivo `pipeline/prd-marketplace/meu-cron/version` pode conter:
55
+
56
+ ```text
57
+ 1.2.3
58
+ ```
59
+
60
+ ## Uso
61
+
62
+ ### Atualizar um job
63
+
64
+ Por padrão, os comandos atuam no ambiente `prd-marketplace`:
65
+
66
+ ```bash
67
+ bumpy job up meu-cron patch
68
+ ```
69
+
70
+ Esse comando altera `1.2.3` para `1.2.4`. Para atualizar outro segmento:
71
+
72
+ ```bash
73
+ bumpy job up meu-cron minor
74
+ bumpy job up meu-cron major
75
+ ```
76
+
77
+ Use `down` para decrementar o segmento. O valor não pode ficar abaixo de zero:
78
+
79
+ ```bash
80
+ bumpy job down meu-cron patch
81
+ ```
82
+
83
+ Para atuar no ambiente `uat`, adicione `--uat`:
84
+
85
+ ```bash
86
+ bumpy job up meu-cron patch --uat
87
+ ```
88
+
89
+ ### Atualizar todos os jobs de um ambiente
90
+
91
+ Os comandos `all` atualizam todos os jobs dentro do ambiente selecionado:
92
+
93
+ ```bash
94
+ bumpy all up patch
95
+ bumpy all down minor
96
+ bumpy all up major --uat
97
+ ```
98
+
99
+ Cada pasta de job do ambiente precisa conter um arquivo `version` válido.
100
+
101
+ ## Ajuda
102
+
103
+ Consulte a ajuda geral ou a de um grupo de comandos:
104
+
105
+ ```bash
106
+ bumpy --help
107
+ bumpy job --help
108
+ bumpy all --help
109
+ ```
110
+
111
+ ## Desenvolvimento
112
+
113
+ O código-fonte, as instruções para contribuir e a documentação do projeto estão
114
+ no [repositorio no GitHub](https://github.com/iamDFSB/Bumpy-CLI).
@@ -0,0 +1,63 @@
1
+ [project]
2
+ name = "bumpy-cli"
3
+ version = "0.1.0"
4
+ description = "CLI para gerenciar versoes de jobs em pipelines."
5
+ authors = [
6
+ {name = "Daniel Felipe Santana Batista",email = "daniel.sbatista@shopee.com"}
7
+ ]
8
+ readme = "README.md"
9
+ requires-python = ">=3.12"
10
+ license = "MIT"
11
+ keywords = ["cli", "pipeline", "versionamento", "jobs"]
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Environment :: Console",
15
+ "Natural Language :: Portuguese (Brazilian)",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Operating System :: OS Independent",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Topic :: Software Development",
22
+ "Topic :: Utilities",
23
+ ]
24
+ dependencies = [
25
+ "typer (>=0.27.2,<0.28.0)"
26
+ ]
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/iamDFSB/Bumpy-CLI"
30
+ Repository = "https://github.com/iamDFSB/Bumpy-CLI"
31
+ Documentation = "https://bumpy-cli.readthedocs.io/pt-br/latest/"
32
+
33
+ [project.scripts]
34
+ bumpy = "bumpy.main:app"
35
+
36
+ [build-system]
37
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
38
+ build-backend = "poetry.core.masonry.api"
39
+
40
+ [tool.poetry]
41
+ packages = [{ include = "bumpy", from = "src" }]
42
+
43
+ [dependency-groups]
44
+ dev = [
45
+ "pytest (>=9.1.1,<10.0.0)",
46
+ "pytest-cov (>=7.1.0,<8.0.0)",
47
+ "blue (>=0.9.1,<0.10.0)",
48
+ "isort (>=9.0.1,<10.0.0)"
49
+ ]
50
+ doc = [
51
+ "mkdocs (>=1.6.1,<2.0.0)",
52
+ "mkdocs-material (>=9.0,<10.0)",
53
+ "mkdocstrings (>=1.0.6,<2.0.0)",
54
+ "mkdocstrings-python (>=2.0.9,<3.0.0)"
55
+ ]
56
+
57
+ [tool.pytest.ini_options]
58
+ pythonpath = "."
59
+ addopts = "--doctest-modules"
60
+
61
+ [tool.isort]
62
+ profile = "black"
63
+ line_length = 79
File without changes
@@ -0,0 +1,4 @@
1
+ from .job import job_app
2
+ from .pipeline import pipeline_app
3
+
4
+ __all__ = ['job_app', 'pipeline_app']
@@ -0,0 +1,49 @@
1
+ import typer
2
+ from rich.console import Console
3
+
4
+ from bumpy.file_client import FileClient
5
+ from bumpy.models import VersionPart
6
+
7
+ # Criamos um sub-app dedicado a ações de "job"
8
+ job_app = typer.Typer(help='Comandos para manipular um unico job especifico.')
9
+ console = Console()
10
+
11
+
12
+ @job_app.command('up')
13
+ def job_up(
14
+ name: str = typer.Argument(..., help='Nome da pasta do job.'),
15
+ part: VersionPart = typer.Argument(
16
+ VersionPart.patch,
17
+ help='Parte da versão a atualizar (major, minor, patch)',
18
+ ),
19
+ uat: bool = typer.Option(
20
+ False, '--uat', help='Aplica no ambiente de UAT.'
21
+ ),
22
+ ):
23
+ """Aumenta a versao de um job especifico."""
24
+ console.print(
25
+ f"[bold green]Aumentando versão do job '{name}'...[/bold green]"
26
+ )
27
+ ambient = 'uat' if uat else 'prd-marketplace'
28
+ path_str = f'{ambient}/{name}/version'
29
+ FileClient().increase(segment=part.value, pipeline_path=path_str)
30
+
31
+
32
+ @job_app.command('down')
33
+ def job_down(
34
+ name: str = typer.Argument(..., help='Nome da pasta do job.'),
35
+ part: VersionPart = typer.Argument(
36
+ VersionPart.patch,
37
+ help='Parte da versão a atualizar (major, minor, patch)',
38
+ ),
39
+ uat: bool = typer.Option(
40
+ False, '--uat', help='Aplica no ambiente de UAT.'
41
+ ),
42
+ ):
43
+ """Diminui a versao de um job especifico."""
44
+ console.print(
45
+ f"[bold yellow]Diminuindo versão do job '{name}'...[/bold yellow]"
46
+ )
47
+ ambient = 'uat' if uat else 'prd-marketplace'
48
+ path_str = f'{ambient}/{name}/version'
49
+ FileClient().decrease(segment=part.value, pipeline_path=path_str)
@@ -0,0 +1,49 @@
1
+ import typer
2
+ from rich.console import Console
3
+
4
+ from bumpy.file_client import FileClient
5
+ from bumpy.models import VersionPart
6
+
7
+ # Criamos um sub-app dedicado a ações do "pipeline" em lote
8
+ pipeline_app = typer.Typer(
9
+ help='Comandos para manipular todos os jobs do pipeline.'
10
+ )
11
+ console = Console()
12
+
13
+
14
+ @pipeline_app.command('up')
15
+ def pipeline_up(
16
+ part: VersionPart = typer.Argument(
17
+ VersionPart.patch,
18
+ help='Parte da versão a atualizar (major, minor, patch)',
19
+ ),
20
+ uat: bool = typer.Option(
21
+ False, '--uat', help='Aplica no ambiente de UAT.'
22
+ ),
23
+ ):
24
+ """Aumenta a versao de TODOS os jobs do pipeline de uma vez."""
25
+ console.print(
26
+ '[bold green]Subindo a versão de todos os jobs no ambiente selecionado...[/bold green]'
27
+ )
28
+ ambient = 'uat' if uat else 'prd-marketplace'
29
+ path_str = f'pipeline/{ambient}'
30
+ FileClient().increase_all(segment=part.value, pipeline_path=path_str)
31
+
32
+
33
+ @pipeline_app.command('down')
34
+ def pipeline_down(
35
+ part: VersionPart = typer.Argument(
36
+ VersionPart.patch,
37
+ help='Parte da versão a atualizar (major, minor, patch)',
38
+ ),
39
+ uat: bool = typer.Option(
40
+ False, '--uat', help='Aplica no ambiente de UAT.'
41
+ ),
42
+ ):
43
+ """Diminui a versao de TODOS os jobs do pipeline de uma vez."""
44
+ console.print(
45
+ '[bold yellow]Diminuindo a versão de todos os jobs no ambiente selecionado...[/bold yellow]'
46
+ )
47
+ ambient = 'uat' if uat else 'prd-marketplace'
48
+ path_str = f'pipeline/{ambient}'
49
+ FileClient().decrease_all(segment=part.value, pipeline_path=path_str)
File without changes
@@ -0,0 +1,23 @@
1
+ class EmptyFileException(Exception):
2
+ def __init__(self, file_name: str):
3
+ message = f'An error occured, the file {file_name} is empty'
4
+ super().__init__(message)
5
+
6
+
7
+ class MissingSegmentsException(ValueError):
8
+ def __init__(self, file_name: str):
9
+ message = f'An error occured, the file {file_name} must have 3 segments (major.minor.patch)'
10
+ super().__init__(message)
11
+
12
+
13
+ class NotFoundPipelinePathException(FileNotFoundError):
14
+ def __init__(self):
15
+ message = 'An error occured, pipeline path was not found'
16
+ super().__init__(message)
17
+
18
+
19
+ class VersionUnderflowError(Exception):
20
+ def __init__(self, file_name: str, version_part: str = 'versão'):
21
+ super().__init__(
22
+ f'An error occured, It is not possible to decrease the {version_part} in {file_name}: the minimum value is 0.'
23
+ )
@@ -0,0 +1,90 @@
1
+ import os
2
+ from pathlib import Path
3
+
4
+ from .exceptions.file_client_exceptions import (
5
+ EmptyFileException,
6
+ MissingSegmentsException,
7
+ NotFoundPipelinePathException,
8
+ VersionUnderflowError,
9
+ )
10
+
11
+
12
+ class FileClient:
13
+ def __init__(self) -> None:
14
+ self.__absolute_path = Path.cwd()
15
+ self.__current_dir = None
16
+ self.__segment = {}
17
+
18
+ def __validate_pipeline_path(self, pipeline_path: str) -> None:
19
+ for f in self.__absolute_path.iterdir():
20
+ list_path = list(f.glob(pipeline_path))
21
+ if list_path:
22
+ self.__current_dir = list_path[0]
23
+ return None
24
+ raise NotFoundPipelinePathException()
25
+
26
+ def __get_current_version(self) -> None:
27
+ with open(self.__current_dir, 'r') as file:
28
+ content = file.read()
29
+ if not content:
30
+ raise EmptyFileException(str(self.__current_dir))
31
+
32
+ version = content.split('.')
33
+ if len(version) < 3:
34
+ raise MissingSegmentsException(str(self.__current_dir))
35
+
36
+ self.__segment['major'] = int(version[0])
37
+ self.__segment['minor'] = int(version[1])
38
+ self.__segment['patch'] = int(version[2])
39
+
40
+ def __update_file_version(self) -> None:
41
+ major = self.__segment['major']
42
+ minor = self.__segment['minor']
43
+ patch = self.__segment['patch']
44
+
45
+ with open(self.__current_dir, 'w') as file:
46
+ new_version = f'{major}.{minor}.{patch}'
47
+ file.write(new_version)
48
+
49
+ def increase(self, segment: str, pipeline_path: str) -> None:
50
+ self.__validate_pipeline_path(pipeline_path)
51
+ self.__get_current_version()
52
+
53
+ self.__segment[segment] += 1
54
+
55
+ self.__update_file_version()
56
+
57
+ def decrease(self, segment: str, pipeline_path: str) -> None:
58
+ self.__validate_pipeline_path(pipeline_path)
59
+ self.__get_current_version()
60
+
61
+ if self.__segment[segment] == 0:
62
+ raise VersionUnderflowError(pipeline_path, segment)
63
+
64
+ self.__segment[segment] -= 1
65
+
66
+ self.__update_file_version()
67
+
68
+ def increase_all(self, segment: str, pipeline_path: str) -> None:
69
+ folder_paths = self.__absolute_path / pipeline_path
70
+
71
+ for folder_name in os.listdir(folder_paths):
72
+ version_path = folder_paths / folder_name / 'version'
73
+ self.__current_dir = version_path
74
+ self.__get_current_version()
75
+ self.__segment[segment] += 1
76
+ self.__update_file_version()
77
+
78
+ def decrease_all(self, segment: str, pipeline_path: str) -> None:
79
+ folder_paths = self.__absolute_path / pipeline_path
80
+
81
+ for folder_name in os.listdir(folder_paths):
82
+ version_path = folder_paths / folder_name / 'version'
83
+ self.__current_dir = version_path
84
+ self.__get_current_version()
85
+
86
+ if self.__segment[segment] == 0:
87
+ raise VersionUnderflowError(folder_name, segment)
88
+
89
+ self.__segment[segment] -= 1
90
+ self.__update_file_version()
@@ -0,0 +1,15 @@
1
+ import typer
2
+
3
+ from bumpy.commands import job_app, pipeline_app
4
+
5
+ # App principal (Raiz da Árvore)
6
+ app = typer.Typer(
7
+ help='Bumpy: Gerenciador de versoes para pipelines multi-plataforma.'
8
+ )
9
+
10
+ # Registrando os galhos/nós na árvore de comandos
11
+ app.add_typer(job_app, name='job')
12
+ app.add_typer(pipeline_app, name='all')
13
+
14
+ if __name__ == '__main__':
15
+ app()
@@ -0,0 +1,10 @@
1
+ from enum import Enum
2
+
3
+
4
+ class VersionPart(str, Enum):
5
+ major = 'major'
6
+ minor = 'minor'
7
+ patch = 'patch'
8
+
9
+ def get_index_position(self):
10
+ return {'major': 0, 'minor': 1, 'patch': 2}[self.value]