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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: git-tide
3
- Version: 0.1.2
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.2"
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
- cz,
12
- get_tag_for_branch,
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, _ in projects:
181
+ for project_folder, project_name in projects:
183
182
  # Auto-tag
184
- tag = get_tag_for_branch(CONFIG, remote, branch, project_folder)
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
- click.echo(get_tag_for_branch(CONFIG, remote, branch, Path(path)))
330
+
331
+ click.echo(get_next_tag(CONFIG, remote, branch, project_name, folder))
321
332
  else:
322
- click.echo(cz("version", "--project", folder=path))
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(config: Config, remote: str, branch: str, folder: Path) -> bool:
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
- cwd = os.getcwd()
506
- os.chdir(folder)
507
- try:
508
- # Use the matching logic from commitizen, which will read the commitizen
509
- # config file for us (note: it supports more than just pyproject.toml).
510
- provider = ScmProvider(read_cfg())
511
- matcher = provider._tag_format_matcher()
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 get_tag_for_branch() will return a minor increment.
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 get_tag_for_branch(config: Config, remote: str, branch: str, folder: Path) -> str:
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
- increment = "patch"
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 = "minor"
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
- args += ["--prerelease", release_id.value]
597
-
598
- if increment == "minor":
599
- args += ["--increment-mode=exact"]
600
-
601
- # run this in the project directory so that the pyproject.toml is accessible.
602
- output = cz(*(["bump"] + list(args) + ["--dry-run", "--yes"]), folder=folder)
603
- match = re.search("tag to create: (.*)", output)
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
- tag = match.group(1).strip()
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 tag
664
+ return new_tag_version
611
665
 
612
666
 
613
- def get_projects() -> list[tuple[Path, str | None]]:
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.commitizen` section.
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"]["commitizen"]
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 | None]]:
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.commitizen` section.
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