git-tide 0.1.2__tar.gz → 0.1.4__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.
- {git_tide-0.1.2 → git_tide-0.1.4}/PKG-INFO +7 -1
- {git_tide-0.1.2 → git_tide-0.1.4}/README.md +6 -0
- {git_tide-0.1.2 → git_tide-0.1.4}/pyproject.toml +2 -8
- {git_tide-0.1.2 → git_tide-0.1.4}/src/tide/cli.py +18 -7
- {git_tide-0.1.2 → git_tide-0.1.4}/src/tide/core.py +99 -48
- {git_tide-0.1.2 → git_tide-0.1.4}/src/tide/__init__.py +0 -0
- {git_tide-0.1.2 → git_tide-0.1.4}/src/tide/__main__.py +0 -0
- {git_tide-0.1.2 → git_tide-0.1.4}/src/tide/gitutils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: git-tide
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: CLI for automated gitflow-style branching
|
|
5
5
|
Author: Chad Dombrova
|
|
6
6
|
Classifier: Programming Language :: Python :: 2
|
|
@@ -100,6 +100,12 @@ In order for `tide` to work its magic, the Gitlab repo needs to be properly conf
|
|
|
100
100
|
branches.rc = "staging"
|
|
101
101
|
branches.stable = "master"
|
|
102
102
|
```
|
|
103
|
+
- For each project within your repo that you want to manage tagged releases, add a `project` entry:
|
|
104
|
+
```toml
|
|
105
|
+
[tool.tide]
|
|
106
|
+
project = "project_name"
|
|
107
|
+
```
|
|
108
|
+
If there is only one, then combine be sure to put all of your options under a single `[tool.tide]` section.
|
|
103
109
|
- Create a [Project Access Token](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html) with the appropriate scope for being able to push tags, changes and create cicd variables.
|
|
104
110
|
- Run `tide init --access-token='YOUR_ACCESS_TOKEN'`
|
|
105
111
|
- Copy and modify the `.gitlab-ci.yml` file ensuring the branch variables match the ones in the `pyproject.toml` (TODO: automated generation of `.gitlab-ci.yml` in `tide init`)
|
|
@@ -76,6 +76,12 @@ In order for `tide` to work its magic, the Gitlab repo needs to be properly conf
|
|
|
76
76
|
branches.rc = "staging"
|
|
77
77
|
branches.stable = "master"
|
|
78
78
|
```
|
|
79
|
+
- For each project within your repo that you want to manage tagged releases, add a `project` entry:
|
|
80
|
+
```toml
|
|
81
|
+
[tool.tide]
|
|
82
|
+
project = "project_name"
|
|
83
|
+
```
|
|
84
|
+
If there is only one, then combine be sure to put all of your options under a single `[tool.tide]` section.
|
|
79
85
|
- Create a [Project Access Token](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html) with the appropriate scope for being able to push tags, changes and create cicd variables.
|
|
80
86
|
- Run `tide init --access-token='YOUR_ACCESS_TOKEN'`
|
|
81
87
|
- Copy and modify the `.gitlab-ci.yml` file ensuring the branch variables match the ones in the `pyproject.toml` (TODO: automated generation of `.gitlab-ci.yml` in `tide init`)
|
|
@@ -6,7 +6,7 @@ name = "git-tide"
|
|
|
6
6
|
packages = [
|
|
7
7
|
{ include = "tide", from = "src" },
|
|
8
8
|
]
|
|
9
|
-
version = "0.1.
|
|
9
|
+
version = "0.1.4"
|
|
10
10
|
description = "CLI for automated gitflow-style branching"
|
|
11
11
|
authors = ["Chad Dombrova", "Matt Collie"]
|
|
12
12
|
readme = "README.md"
|
|
@@ -41,13 +41,7 @@ markers = [
|
|
|
41
41
|
]
|
|
42
42
|
|
|
43
43
|
[tool.tide]
|
|
44
|
+
tag_format = "$version"
|
|
44
45
|
branches.beta = "develop"
|
|
45
46
|
branches.rc = "staging"
|
|
46
47
|
branches.stable = "master"
|
|
47
|
-
|
|
48
|
-
[tool.commitizen]
|
|
49
|
-
name = "cz_conventional_commits"
|
|
50
|
-
tag_format = "$version"
|
|
51
|
-
version_scheme = "pep440"
|
|
52
|
-
version_provider = "scm"
|
|
53
|
-
major_version_zero = false
|
|
@@ -8,8 +8,8 @@ from pathlib import Path
|
|
|
8
8
|
|
|
9
9
|
from .core import (
|
|
10
10
|
is_url,
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
get_next_tag,
|
|
12
|
+
get_current_tag,
|
|
13
13
|
get_modified_projects,
|
|
14
14
|
get_projects,
|
|
15
15
|
load_config,
|
|
@@ -54,7 +54,6 @@ def get_runtime() -> Runtime:
|
|
|
54
54
|
"""
|
|
55
55
|
Return a Runtime corresponding to where the current python process is *running*
|
|
56
56
|
"""
|
|
57
|
-
print(os.environ.get("GITLAB_CI"))
|
|
58
57
|
if os.environ.get("GITLAB_CI", "false") == "true":
|
|
59
58
|
return GitlabRuntime(CONFIG)
|
|
60
59
|
# gitlab-ci-local and our unittests set this to false as an inidicator that
|
|
@@ -179,9 +178,9 @@ def autotag(annotation: str, base_rev: str | None) -> None:
|
|
|
179
178
|
|
|
180
179
|
projects = get_modified_projects(base_rev, verbose=CONFIG.verbose)
|
|
181
180
|
if projects:
|
|
182
|
-
for project_folder,
|
|
181
|
+
for project_folder, project_name in projects:
|
|
183
182
|
# Auto-tag
|
|
184
|
-
tag =
|
|
183
|
+
tag = get_next_tag(CONFIG, remote, branch, project_name, project_folder)
|
|
185
184
|
|
|
186
185
|
# NOTE: this delay is necessary to create stable sorting of tags
|
|
187
186
|
# because git's time resolution is 1s (same as unix timestamp).
|
|
@@ -313,13 +312,25 @@ def get_tag(path: str, branch: str | None, remote: str, next: bool) -> None:
|
|
|
313
312
|
"""
|
|
314
313
|
Get the next tag.
|
|
315
314
|
"""
|
|
315
|
+
projects = dict(get_projects())
|
|
316
|
+
folder = Path(path)
|
|
317
|
+
try:
|
|
318
|
+
project_name = projects[folder]
|
|
319
|
+
except KeyError:
|
|
320
|
+
raise click.ClickException(
|
|
321
|
+
f"There is not a project at path={folder}. "
|
|
322
|
+
"Ensure there is a pyproject.toml file with a [tool.tide] section "
|
|
323
|
+
"and a `project` entry"
|
|
324
|
+
)
|
|
325
|
+
|
|
316
326
|
if next:
|
|
317
327
|
if branch is None:
|
|
318
328
|
runtime = get_runtime()
|
|
319
329
|
branch = runtime.current_branch()
|
|
320
|
-
|
|
330
|
+
|
|
331
|
+
click.echo(get_next_tag(CONFIG, remote, branch, project_name, folder))
|
|
321
332
|
else:
|
|
322
|
-
click.echo(
|
|
333
|
+
click.echo(get_current_tag(CONFIG, project_name, folder))
|
|
323
334
|
|
|
324
335
|
|
|
325
336
|
def main() -> None:
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import absolute_import, print_function, annotations
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
-
import re
|
|
5
4
|
import subprocess
|
|
6
5
|
import json
|
|
7
6
|
|
|
@@ -23,6 +22,8 @@ from .gitutils import git, checkout, get_tags, branch_exists, join, current_rev,
|
|
|
23
22
|
|
|
24
23
|
if TYPE_CHECKING:
|
|
25
24
|
import gitlab.v4.objects
|
|
25
|
+
import commitizen.providers
|
|
26
|
+
import commitizen.config
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
TOOL_NAME = "tide"
|
|
@@ -83,6 +84,12 @@ def load_config(path: str | None = None, verbose: bool = False) -> Config:
|
|
|
83
84
|
)
|
|
84
85
|
|
|
85
86
|
config = Config(verbose=verbose)
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
config.tag_format = settings["tag_format"]
|
|
90
|
+
except KeyError:
|
|
91
|
+
pass
|
|
92
|
+
|
|
86
93
|
# Loop through branches once and extract all needed information
|
|
87
94
|
for release_id in ReleaseID:
|
|
88
95
|
branch_name = branches.get(release_id.value)
|
|
@@ -109,6 +116,7 @@ class Config:
|
|
|
109
116
|
# branch name to pre-release name (alpha, beta, rc). None for stable.
|
|
110
117
|
branch_to_release_id: dict[str, ReleaseID] = field(default_factory=dict)
|
|
111
118
|
verbose: bool = False
|
|
119
|
+
tag_format: str = "$version"
|
|
112
120
|
|
|
113
121
|
def get_upstream_branch(self, branch: str) -> str | None:
|
|
114
122
|
"""
|
|
@@ -477,7 +485,13 @@ def cz(*args: str, folder: str | Path | None = None) -> str:
|
|
|
477
485
|
return output.strip()
|
|
478
486
|
|
|
479
487
|
|
|
480
|
-
def is_pending_bump(
|
|
488
|
+
def is_pending_bump(
|
|
489
|
+
config: Config,
|
|
490
|
+
provider: commitizen.providers.ScmProvider,
|
|
491
|
+
remote: str,
|
|
492
|
+
branch: str,
|
|
493
|
+
folder: Path,
|
|
494
|
+
) -> bool:
|
|
481
495
|
"""
|
|
482
496
|
Return whether the given branch and folder combination are awaiting a minor bump.
|
|
483
497
|
|
|
@@ -489,9 +503,6 @@ def is_pending_bump(config: Config, remote: str, branch: str, folder: Path) -> b
|
|
|
489
503
|
Returns:
|
|
490
504
|
whether it is pending or not
|
|
491
505
|
"""
|
|
492
|
-
from commitizen.config import read_cfg
|
|
493
|
-
from commitizen.providers import ScmProvider
|
|
494
|
-
|
|
495
506
|
if branch != config.most_experimental_branch():
|
|
496
507
|
return False
|
|
497
508
|
|
|
@@ -502,21 +513,13 @@ def is_pending_bump(config: Config, remote: str, branch: str, folder: Path) -> b
|
|
|
502
513
|
click.echo("No promote marker found", err=True)
|
|
503
514
|
return True
|
|
504
515
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
if config.verbose:
|
|
513
|
-
click.echo(f"Found promotion base rev: {promotion_rev}")
|
|
514
|
-
# List any tags for this project folder between this branch and the promotion note
|
|
515
|
-
all_tags = get_tags(end_rev=promotion_rev)
|
|
516
|
-
tags = [t for t in all_tags if matcher(t)]
|
|
517
|
-
return not tags
|
|
518
|
-
finally:
|
|
519
|
-
os.chdir(cwd)
|
|
516
|
+
matcher = provider._tag_format_matcher()
|
|
517
|
+
if config.verbose:
|
|
518
|
+
click.echo(f"Found promotion base rev: {promotion_rev}")
|
|
519
|
+
# List any tags for this project folder between this branch and the promotion note
|
|
520
|
+
all_tags = get_tags(end_rev=promotion_rev)
|
|
521
|
+
tags = [t for t in all_tags if matcher(t)]
|
|
522
|
+
return not tags
|
|
520
523
|
|
|
521
524
|
|
|
522
525
|
def get_promotion_marker(remote: str) -> str | None:
|
|
@@ -544,7 +547,7 @@ def set_promotion_marker(remote: str, branch: str) -> None:
|
|
|
544
547
|
"""
|
|
545
548
|
Store a state for whether the given project on the given branch needs to have a minor bump.
|
|
546
549
|
|
|
547
|
-
If it is true for a given branch, then
|
|
550
|
+
If it is true for a given branch, then get_next_tag() will return a minor increment.
|
|
548
551
|
After this, autotag() will set the pending state to False until.
|
|
549
552
|
|
|
550
553
|
This pending state is reset to True after each promotion event.
|
|
@@ -559,7 +562,45 @@ def set_promotion_marker(remote: str, branch: str) -> None:
|
|
|
559
562
|
git("push", remote, "refs/notes/*")
|
|
560
563
|
|
|
561
564
|
|
|
562
|
-
def
|
|
565
|
+
def _get_cz_config(config: Config, project_name: str) -> commitizen.config.BaseConfig:
|
|
566
|
+
from commitizen.config.base_config import BaseConfig
|
|
567
|
+
from commitizen.defaults import Settings
|
|
568
|
+
|
|
569
|
+
cz_config = BaseConfig()
|
|
570
|
+
cz_config.update(
|
|
571
|
+
Settings(
|
|
572
|
+
name="cz_conventional_commits",
|
|
573
|
+
tag_format=config.tag_format.replace("$project", project_name),
|
|
574
|
+
version_scheme="pep440",
|
|
575
|
+
version_provider="scm",
|
|
576
|
+
major_version_zero=False,
|
|
577
|
+
)
|
|
578
|
+
)
|
|
579
|
+
return cz_config
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
def get_current_tag(config: Config, project_name: str, folder: Path) -> str:
|
|
583
|
+
from commitizen.providers import ScmProvider
|
|
584
|
+
from commitizen.version_schemes import get_version_scheme
|
|
585
|
+
from commitizen import bump
|
|
586
|
+
|
|
587
|
+
cz_config = _get_cz_config(config, project_name)
|
|
588
|
+
provider = ScmProvider(cz_config)
|
|
589
|
+
scheme = get_version_scheme(cz_config)
|
|
590
|
+
current_version = provider.get_version()
|
|
591
|
+
|
|
592
|
+
tag_version = bump.normalize_tag(
|
|
593
|
+
current_version,
|
|
594
|
+
tag_format=cz_config.settings["tag_format"],
|
|
595
|
+
scheme=scheme,
|
|
596
|
+
)
|
|
597
|
+
|
|
598
|
+
return tag_version
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
def get_next_tag(
|
|
602
|
+
config: Config, remote: str, branch: str, project_name: str, folder: Path
|
|
603
|
+
) -> str:
|
|
563
604
|
"""
|
|
564
605
|
Determine the appropriate new tag for a given branch based on the latest changes.
|
|
565
606
|
|
|
@@ -577,6 +618,10 @@ def get_tag_for_branch(config: Config, remote: str, branch: str, folder: Path) -
|
|
|
577
618
|
Raises:
|
|
578
619
|
RuntimeError: If the command does not generate an output or fails to determine the tag.
|
|
579
620
|
"""
|
|
621
|
+
from commitizen.providers import ScmProvider
|
|
622
|
+
from commitizen.version_schemes import get_version_scheme, Increment
|
|
623
|
+
from commitizen import bump
|
|
624
|
+
|
|
580
625
|
try:
|
|
581
626
|
release_id = config.branch_to_release_id[branch]
|
|
582
627
|
except KeyError:
|
|
@@ -585,35 +630,45 @@ def get_tag_for_branch(config: Config, remote: str, branch: str, folder: Path) -
|
|
|
585
630
|
f"Must be one of {', '.join(config.branches)}"
|
|
586
631
|
)
|
|
587
632
|
|
|
588
|
-
|
|
633
|
+
cz_config = _get_cz_config(config, project_name)
|
|
634
|
+
|
|
635
|
+
provider = ScmProvider(cz_config)
|
|
636
|
+
scheme = get_version_scheme(cz_config)
|
|
637
|
+
current_version = scheme(provider.get_version())
|
|
589
638
|
|
|
590
639
|
# Only apply minor increment the most experimental branch
|
|
591
|
-
if is_pending_bump(config, remote, branch, folder):
|
|
592
|
-
increment = "
|
|
640
|
+
if is_pending_bump(config, provider, remote, branch, folder):
|
|
641
|
+
increment: Increment = "MINOR"
|
|
642
|
+
exact_increment = True
|
|
643
|
+
else:
|
|
644
|
+
increment = "PATCH"
|
|
645
|
+
exact_increment = False
|
|
593
646
|
|
|
594
|
-
args = [f"--increment={increment}"]
|
|
595
647
|
if release_id != ReleaseID.stable:
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
if not match:
|
|
606
|
-
raise click.ClickException(output)
|
|
648
|
+
prerelease = release_id.value
|
|
649
|
+
else:
|
|
650
|
+
prerelease = None
|
|
651
|
+
|
|
652
|
+
new_version = current_version.bump(
|
|
653
|
+
increment,
|
|
654
|
+
prerelease=prerelease,
|
|
655
|
+
exact_increment=exact_increment,
|
|
656
|
+
)
|
|
607
657
|
|
|
608
|
-
|
|
658
|
+
new_tag_version = bump.normalize_tag(
|
|
659
|
+
new_version,
|
|
660
|
+
tag_format=cz_config.settings["tag_format"],
|
|
661
|
+
scheme=scheme,
|
|
662
|
+
)
|
|
609
663
|
|
|
610
|
-
return
|
|
664
|
+
return new_tag_version
|
|
611
665
|
|
|
612
666
|
|
|
613
|
-
def get_projects() -> list[tuple[Path, str
|
|
667
|
+
def get_projects() -> list[tuple[Path, str]]:
|
|
614
668
|
"""Get the list of projects within the repo.
|
|
615
669
|
|
|
616
|
-
A project is a folder with a pyproject.toml file with a `tool.
|
|
670
|
+
A project is a folder with a pyproject.toml file with a `tool.tide` section
|
|
671
|
+
and a `tool.tide.project`.
|
|
617
672
|
"""
|
|
618
673
|
results = []
|
|
619
674
|
repo = GitRepo(".")
|
|
@@ -621,24 +676,20 @@ def get_projects() -> list[tuple[Path, str | None]]:
|
|
|
621
676
|
with open(path, "rb") as f:
|
|
622
677
|
data = tomllib.load(f)
|
|
623
678
|
try:
|
|
624
|
-
data["tool"]["
|
|
679
|
+
name = data["tool"][TOOL_NAME]["project"]
|
|
625
680
|
except KeyError:
|
|
626
681
|
pass
|
|
627
682
|
else:
|
|
628
|
-
try:
|
|
629
|
-
name = data["project"]["name"]
|
|
630
|
-
except KeyError:
|
|
631
|
-
name = None
|
|
632
683
|
results.append((Path(path).parent, name))
|
|
633
684
|
return sorted(results)
|
|
634
685
|
|
|
635
686
|
|
|
636
687
|
def get_modified_projects(
|
|
637
688
|
base_rev: str, verbose: bool = False
|
|
638
|
-
) -> list[tuple[Path, str
|
|
689
|
+
) -> list[tuple[Path, str]]:
|
|
639
690
|
"""Get the list of projects with changes files.
|
|
640
691
|
|
|
641
|
-
A project is defined as a folder with a pyproject.toml file with a `tool.
|
|
692
|
+
A project is defined as a folder with a pyproject.toml file with a `tool.tide` section.
|
|
642
693
|
|
|
643
694
|
Args:
|
|
644
695
|
base_rev: The Git revision to compare against when identifying changed files
|
|
File without changes
|
|
File without changes
|
|
File without changes
|