crackerjack 0.15.10__py3-none-any.whl → 0.16.0__py3-none-any.whl

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.
crackerjack/__main__.py CHANGED
@@ -33,6 +33,7 @@ class Options(BaseModel):
33
33
  test: bool = False
34
34
  all: BumpOption | None = None
35
35
  ai_agent: bool = False
36
+ create_pr: bool = False
36
37
 
37
38
  @classmethod
38
39
  @field_validator("publish", "bump", mode="before")
@@ -89,6 +90,12 @@ cli_options = {
89
90
  help="Run with `-x -t -p <micro|minor|major> -c` development options).",
90
91
  case_sensitive=False,
91
92
  ),
93
+ "create_pr": typer.Option(
94
+ False,
95
+ "-r",
96
+ "--pr",
97
+ help="Create a pull request to the upstream repository.",
98
+ ),
92
99
  "ai_agent": typer.Option(
93
100
  False,
94
101
  "--ai-agent",
@@ -111,6 +118,7 @@ def main(
111
118
  bump: BumpOption | None = cli_options["bump"],
112
119
  clean: bool = cli_options["clean"],
113
120
  test: bool = cli_options["test"],
121
+ create_pr: bool = cli_options["create_pr"],
114
122
  ai_agent: bool = cli_options["ai_agent"],
115
123
  ) -> None:
116
124
  options = Options(
@@ -126,6 +134,7 @@ def main(
126
134
  test=test,
127
135
  all=all,
128
136
  ai_agent=ai_agent,
137
+ create_pr=create_pr,
129
138
  )
130
139
 
131
140
  if ai_agent:
@@ -43,6 +43,7 @@ class OptionsProtocol(t.Protocol):
43
43
  bump: t.Any | None
44
44
  all: t.Any | None
45
45
  ai_agent: bool = False
46
+ create_pr: bool = False
46
47
 
47
48
 
48
49
  @dataclass
@@ -679,6 +680,159 @@ class Crackerjack:
679
680
  )
680
681
  self.execute_command(["git", "push", "origin", "main"])
681
682
 
683
+ def _create_pull_request(self, options: OptionsProtocol) -> None:
684
+ if options.create_pr:
685
+ self.console.print("\nCreating pull request...")
686
+
687
+ # Get the current branch name
688
+ current_branch = self.execute_command(
689
+ ["git", "branch", "--show-current"], capture_output=True, text=True
690
+ ).stdout.strip()
691
+
692
+ # Get the remote URL to determine if it's GitHub or GitLab
693
+ remote_url = self.execute_command(
694
+ ["git", "remote", "get-url", "origin"], capture_output=True, text=True
695
+ ).stdout.strip()
696
+
697
+ # Determine if we're using GitHub or GitLab
698
+ is_github = "github.com" in remote_url
699
+ is_gitlab = "gitlab.com" in remote_url
700
+
701
+ if is_github:
702
+ # Check if GitHub CLI is installed
703
+ gh_installed = (
704
+ self.execute_command(
705
+ ["which", "gh"], capture_output=True, text=True
706
+ ).returncode
707
+ == 0
708
+ )
709
+
710
+ if not gh_installed:
711
+ self.console.print(
712
+ "\n[red]GitHub CLI (gh) is not installed. Please install it first:[/red]\n"
713
+ " brew install gh # for macOS\n"
714
+ " or visit https://cli.github.com/ for other installation methods"
715
+ )
716
+ return
717
+
718
+ # Check if user is authenticated with GitHub
719
+ auth_status = self.execute_command(
720
+ ["gh", "auth", "status"], capture_output=True, text=True
721
+ ).returncode
722
+
723
+ if auth_status != 0:
724
+ self.console.print(
725
+ "\n[red]You need to authenticate with GitHub first. Run:[/red]\n"
726
+ " gh auth login"
727
+ )
728
+ return
729
+
730
+ # Prompt for PR title and description
731
+ pr_title = input("\nEnter a title for your pull request: ")
732
+ self.console.print(
733
+ "Enter a description for your pull request (press Ctrl+D when done):"
734
+ )
735
+ pr_description = ""
736
+ with suppress(EOFError):
737
+ pr_description = "".join(iter(input, ""))
738
+
739
+ # Create the pull request
740
+ self.console.print("Creating pull request to GitHub repository...")
741
+ result = self.execute_command(
742
+ [
743
+ "gh",
744
+ "pr",
745
+ "create",
746
+ "--title",
747
+ pr_title,
748
+ "--body",
749
+ pr_description,
750
+ ],
751
+ capture_output=True,
752
+ text=True,
753
+ )
754
+
755
+ if result.returncode == 0:
756
+ self.console.print(
757
+ f"\n[green]Pull request created successfully![/green]\n{result.stdout}"
758
+ )
759
+ else:
760
+ self.console.print(
761
+ f"\n[red]Failed to create pull request:[/red]\n{result.stderr}"
762
+ )
763
+
764
+ elif is_gitlab:
765
+ # Check if GitLab CLI is installed
766
+ glab_installed = (
767
+ self.execute_command(
768
+ ["which", "glab"], capture_output=True, text=True
769
+ ).returncode
770
+ == 0
771
+ )
772
+
773
+ if not glab_installed:
774
+ self.console.print(
775
+ "\n[red]GitLab CLI (glab) is not installed. Please install it first:[/red]\n"
776
+ " brew install glab # for macOS\n"
777
+ " or visit https://gitlab.com/gitlab-org/cli for other installation methods"
778
+ )
779
+ return
780
+
781
+ # Check if user is authenticated with GitLab
782
+ auth_status = self.execute_command(
783
+ ["glab", "auth", "status"], capture_output=True, text=True
784
+ ).returncode
785
+
786
+ if auth_status != 0:
787
+ self.console.print(
788
+ "\n[red]You need to authenticate with GitLab first. Run:[/red]\n"
789
+ " glab auth login"
790
+ )
791
+ return
792
+
793
+ # Prompt for MR title and description
794
+ mr_title = input("\nEnter a title for your merge request: ")
795
+ self.console.print(
796
+ "Enter a description for your merge request (press Ctrl+D when done):"
797
+ )
798
+ mr_description = ""
799
+ with suppress(EOFError):
800
+ mr_description = "".join(iter(input, ""))
801
+
802
+ # Create the merge request
803
+ self.console.print("Creating merge request to GitLab repository...")
804
+ result = self.execute_command(
805
+ [
806
+ "glab",
807
+ "mr",
808
+ "create",
809
+ "--title",
810
+ mr_title,
811
+ "--description",
812
+ mr_description,
813
+ "--source-branch",
814
+ current_branch,
815
+ "--target-branch",
816
+ "main",
817
+ ],
818
+ capture_output=True,
819
+ text=True,
820
+ )
821
+
822
+ if result.returncode == 0:
823
+ self.console.print(
824
+ f"\n[green]Merge request created successfully![/green]\n{result.stdout}"
825
+ )
826
+ else:
827
+ self.console.print(
828
+ f"\n[red]Failed to create merge request:[/red]\n{result.stderr}"
829
+ )
830
+ else:
831
+ self.console.print(
832
+ f"\n[red]Unsupported git hosting service: {remote_url}[/red]\n"
833
+ "This command currently supports GitHub and GitLab."
834
+ )
835
+
682
836
  def execute_command(
683
837
  self, cmd: list[str], **kwargs: t.Any
684
838
  ) -> subprocess.CompletedProcess[str]:
@@ -734,6 +888,10 @@ class Crackerjack:
734
888
  if options.commit:
735
889
  actions_performed.append("commit_and_push")
736
890
 
891
+ self._create_pull_request(options)
892
+ if options.create_pr:
893
+ actions_performed.append("create_pull_request")
894
+
737
895
  # Check if we're being called by an AI agent
738
896
  if getattr(options, "ai_agent", False):
739
897
  # Use structured output for AI agents
@@ -150,7 +150,7 @@ pythonPlatform = "Darwin"
150
150
 
151
151
  [project]
152
152
  name = "crackerjack"
153
- version = "0.15.9"
153
+ version = "0.15.10"
154
154
  description = "Default template for PDM package"
155
155
  requires-python = ">=3.13"
156
156
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: crackerjack
3
- Version: 0.15.10
3
+ Version: 0.16.0
4
4
  Summary: Default template for PDM package
5
5
  Keywords: black,ruff,mypy,creosote,refurb
6
6
  Author-Email: lesleslie <les@wedgwoodwebworks.com>
@@ -103,6 +103,7 @@ Crackerjack provides:
103
103
  - **Easy Version Bumping:** Provides commands to bump the project version (micro, minor, or major).
104
104
  - **Simplified Publishing:** Automates publishing to PyPI via PDM.
105
105
  - **Commit and Push:** Commits and pushes your changes.
106
+ - **Pull Request Creation:** Creates pull requests to upstream repositories on GitHub or GitLab.
106
107
 
107
108
  ## Pre-commit Hooks
108
109
 
@@ -188,6 +189,7 @@ class MyOptions:
188
189
  self.publish = None
189
190
  self.bump = "micro"
190
191
  self.all = None
192
+ self.create_pr = False
191
193
 
192
194
  # Create a Crackerjack runner with custom settings
193
195
  runner = create_crackerjack_runner(
@@ -211,6 +213,7 @@ runner.process(MyOptions())
211
213
  - `-v`, `--verbose`: Enable verbose output.
212
214
  - `-p`, `--publish <micro|minor|major>`: Bump the project version and publish to PyPI using PDM.
213
215
  - `-b`, `--bump <micro|minor|major>`: Bump the project version without publishing.
216
+ - `-r`, `--pr`: Create a pull request to the upstream repository.
214
217
  - `-x`, `--clean`: Clean code by removing docstrings, line comments, and extra whitespace.
215
218
  - `-t`, `--test`: Run tests using `pytest`.
216
219
  - `-a`, `--all`: Run with `-x -t -p <micro|minor|major> -c` development options.
@@ -248,6 +251,11 @@ runner.process(MyOptions())
248
251
  python -m crackerjack -u
249
252
  ```
250
253
 
254
+ - **Create a pull request to the upstream repository:**
255
+ ```
256
+ python -m crackerjack -r
257
+ ```
258
+
251
259
  - **Get help:**
252
260
  ```
253
261
  python -m crackerjack --help
@@ -1,7 +1,7 @@
1
- crackerjack-0.15.10.dist-info/METADATA,sha256=InLwW916jxaIvZ3PzWakEG1yXKNHrAN1pXy0b-6jcHw,12899
2
- crackerjack-0.15.10.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
3
- crackerjack-0.15.10.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
- crackerjack-0.15.10.dist-info/licenses/LICENSE,sha256=fDt371P6_6sCu7RyqiZH_AhT1LdN3sN1zjBtqEhDYCk,1531
1
+ crackerjack-0.16.0.dist-info/METADATA,sha256=MYUBgU4OZEhpRTkR7xgUq_kpY2tUPTKSfUxKneqzovI,13198
2
+ crackerjack-0.16.0.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
3
+ crackerjack-0.16.0.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
+ crackerjack-0.16.0.dist-info/licenses/LICENSE,sha256=fDt371P6_6sCu7RyqiZH_AhT1LdN3sN1zjBtqEhDYCk,1531
5
5
  crackerjack/.coverage,sha256=dLzPzp72qZEXohNfxnOAlRwvM9dqF06-HoFqfvXZd1U,53248
6
6
  crackerjack/.gitignore,sha256=oho3dNx7a7y36_y9AsalCkssU4in0MMsNAANWdc-h1c,153
7
7
  crackerjack/.libcst.codemod.yaml,sha256=a8DlErRAIPV1nE6QlyXPAzTOgkB24_spl2E9hphuf5s,772
@@ -25,7 +25,7 @@ crackerjack/.ruff_cache/0.11.4/9818742842212983150,sha256=QF9j6-3MH_d0pDNotdbF2h
25
25
  crackerjack/.ruff_cache/0.11.6/3557596832929915217,sha256=yR2iXWDkSHVRw2eTiaCE8Eh34JPRUGc8vE3HYEEBk9k,224
26
26
  crackerjack/.ruff_cache/0.11.7/10386934055395314831,sha256=lBNwN5zAgM4OzbkXIOzCczUtfooATrD10htj9ASlFkc,224
27
27
  crackerjack/.ruff_cache/0.11.7/3557596832929915217,sha256=fKlwUbsvT3YIKV6UR-aA_i64lLignWeVfVu-MMmVbU0,207
28
- crackerjack/.ruff_cache/0.11.8/530407680854991027,sha256=3SpPDsyKWKQbLDpgEY5rAdUjW_hF4HuOe7ZCrAc1hi0,224
28
+ crackerjack/.ruff_cache/0.11.8/530407680854991027,sha256=vY6TL3JxF2uAWURP-oNnw8Nni9A9uL8kJjfg0T4XF3o,224
29
29
  crackerjack/.ruff_cache/0.2.0/10047773857155985907,sha256=j9LNa_RQ4Plor7go1uTYgz17cEENKvZQ-dP6b9MX0ik,248
30
30
  crackerjack/.ruff_cache/0.2.1/8522267973936635051,sha256=u_aPBMibtAp_iYvLwR88GMAECMcIgHezxMyuapmU2P4,248
31
31
  crackerjack/.ruff_cache/0.2.2/18053836298936336950,sha256=Xb_ebP0pVuUfSqPEZKlhQ70so_vqkEfMYpuHQ06iR5U,248
@@ -54,7 +54,7 @@ crackerjack/.ruff_cache/0.9.9/12813592349865671909,sha256=tmr8_vhRD2OxsVuMfbJPdT
54
54
  crackerjack/.ruff_cache/0.9.9/8843823720003377982,sha256=e4ymkXfQsUg5e_mtO34xTsaTvs1uA3_fI216Qq9qCAM,136
55
55
  crackerjack/.ruff_cache/CACHEDIR.TAG,sha256=WVMVbX4MVkpCclExbq8m-IcOZIOuIZf5FrYw5Pk-Ma4,43
56
56
  crackerjack/__init__.py,sha256=r9SuEjHUrW99hFWifRk4ofmYPSgf9rblcnzqhdV5bP0,157
57
- crackerjack/__main__.py,sha256=vgylaqzoqYUjYstAOQLOU-odCtYarb2oAFBQdzYdar0,4037
58
- crackerjack/crackerjack.py,sha256=IHe1JDIS3Ng_0VW4SjS0HNaKQrRLEu6KAr0bMOFZrro,29114
59
- crackerjack/pyproject.toml,sha256=V0Ru1LG-E5mRnNFMAJCkYOA8J_xvsLvR0NQguse4gc0,4139
60
- crackerjack-0.15.10.dist-info/RECORD,,
57
+ crackerjack/__main__.py,sha256=O2BZxkwH8FKIhQJyWEaLAxvFT2pRGSyr4J7nXpDKV9U,4291
58
+ crackerjack/crackerjack.py,sha256=jZ-giToWrfXR13lIQfEN7pSd2T-F9WAkD5VkkOfuoEc,35451
59
+ crackerjack/pyproject.toml,sha256=yC7E9G8aYuaOwlk59cmMW4atBjMzJDgDyeEkRmqkD4Q,4140
60
+ crackerjack-0.16.0.dist-info/RECORD,,