crackerjack 0.15.10__tar.gz → 0.16.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.
Files changed (69) hide show
  1. {crackerjack-0.15.10 → crackerjack-0.16.0}/PKG-INFO +9 -1
  2. {crackerjack-0.15.10 → crackerjack-0.16.0}/README.md +8 -0
  3. crackerjack-0.16.0/crackerjack/.ruff_cache/0.11.8/530407680854991027 +0 -0
  4. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/__main__.py +9 -0
  5. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/crackerjack.py +158 -0
  6. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/pyproject.toml +1 -1
  7. {crackerjack-0.15.10 → crackerjack-0.16.0}/pyproject.toml +1 -1
  8. {crackerjack-0.15.10 → crackerjack-0.16.0}/tests/test_crackerjack.py +1 -0
  9. {crackerjack-0.15.10 → crackerjack-0.16.0}/tests/test_crackerjack_runner.py +1 -0
  10. {crackerjack-0.15.10 → crackerjack-0.16.0}/tests/test_main.py +18 -0
  11. crackerjack-0.15.10/crackerjack/.ruff_cache/0.11.8/530407680854991027 +0 -0
  12. {crackerjack-0.15.10 → crackerjack-0.16.0}/LICENSE +0 -0
  13. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.coverage +0 -0
  14. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.gitignore +0 -0
  15. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.libcst.codemod.yaml +0 -0
  16. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.pdm.toml +0 -0
  17. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.pre-commit-config.yaml +0 -0
  18. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.pytest_cache/.gitignore +0 -0
  19. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.pytest_cache/CACHEDIR.TAG +0 -0
  20. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.pytest_cache/README.md +0 -0
  21. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.pytest_cache/v/cache/nodeids +0 -0
  22. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.pytest_cache/v/cache/stepwise +0 -0
  23. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/.gitignore +0 -0
  24. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.1.11/3256171999636029978 +0 -0
  25. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.1.14/602324811142551221 +0 -0
  26. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.1.4/10355199064880463147 +0 -0
  27. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.1.6/15140459877605758699 +0 -0
  28. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.1.7/1790508110482614856 +0 -0
  29. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.1.9/17041001205004563469 +0 -0
  30. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.11.2/4070660268492669020 +0 -0
  31. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.11.3/9818742842212983150 +0 -0
  32. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.11.4/9818742842212983150 +0 -0
  33. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.11.6/3557596832929915217 +0 -0
  34. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.11.7/10386934055395314831 +0 -0
  35. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.11.7/3557596832929915217 +0 -0
  36. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.2.0/10047773857155985907 +0 -0
  37. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.2.1/8522267973936635051 +0 -0
  38. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.2.2/18053836298936336950 +0 -0
  39. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.3.0/12548816621480535786 +0 -0
  40. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.3.3/11081883392474770722 +0 -0
  41. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.3.4/676973378459347183 +0 -0
  42. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.3.5/16311176246009842383 +0 -0
  43. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.5.7/1493622539551733492 +0 -0
  44. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.5.7/6231957614044513175 +0 -0
  45. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.5.7/9932762556785938009 +0 -0
  46. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.6.0/11982804814124138945 +0 -0
  47. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.6.0/12055761203849489982 +0 -0
  48. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.6.2/1206147804896221174 +0 -0
  49. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.6.4/1206147804896221174 +0 -0
  50. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.6.5/1206147804896221174 +0 -0
  51. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.6.7/3657366982708166874 +0 -0
  52. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.6.9/285614542852677309 +0 -0
  53. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.7.1/1024065805990144819 +0 -0
  54. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.7.1/285614542852677309 +0 -0
  55. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.7.3/16061516852537040135 +0 -0
  56. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.8.4/16354268377385700367 +0 -0
  57. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.9.10/12813592349865671909 +0 -0
  58. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.9.10/923908772239632759 +0 -0
  59. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.9.3/13948373885254993391 +0 -0
  60. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.9.9/12813592349865671909 +0 -0
  61. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/0.9.9/8843823720003377982 +0 -0
  62. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/.ruff_cache/CACHEDIR.TAG +0 -0
  63. {crackerjack-0.15.10 → crackerjack-0.16.0}/crackerjack/__init__.py +0 -0
  64. {crackerjack-0.15.10 → crackerjack-0.16.0}/tests/README.md +0 -0
  65. {crackerjack-0.15.10 → crackerjack-0.16.0}/tests/__init__.py +0 -0
  66. {crackerjack-0.15.10 → crackerjack-0.16.0}/tests/data/comments_sample.txt +0 -0
  67. {crackerjack-0.15.10 → crackerjack-0.16.0}/tests/data/docstrings_sample.txt +0 -0
  68. {crackerjack-0.15.10 → crackerjack-0.16.0}/tests/data/expected_comments_sample.txt +0 -0
  69. {crackerjack-0.15.10 → crackerjack-0.16.0}/tests/data/init.py +0 -0
@@ -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
@@ -63,6 +63,7 @@ Crackerjack provides:
63
63
  - **Easy Version Bumping:** Provides commands to bump the project version (micro, minor, or major).
64
64
  - **Simplified Publishing:** Automates publishing to PyPI via PDM.
65
65
  - **Commit and Push:** Commits and pushes your changes.
66
+ - **Pull Request Creation:** Creates pull requests to upstream repositories on GitHub or GitLab.
66
67
 
67
68
  ## Pre-commit Hooks
68
69
 
@@ -148,6 +149,7 @@ class MyOptions:
148
149
  self.publish = None
149
150
  self.bump = "micro"
150
151
  self.all = None
152
+ self.create_pr = False
151
153
 
152
154
  # Create a Crackerjack runner with custom settings
153
155
  runner = create_crackerjack_runner(
@@ -171,6 +173,7 @@ runner.process(MyOptions())
171
173
  - `-v`, `--verbose`: Enable verbose output.
172
174
  - `-p`, `--publish <micro|minor|major>`: Bump the project version and publish to PyPI using PDM.
173
175
  - `-b`, `--bump <micro|minor|major>`: Bump the project version without publishing.
176
+ - `-r`, `--pr`: Create a pull request to the upstream repository.
174
177
  - `-x`, `--clean`: Clean code by removing docstrings, line comments, and extra whitespace.
175
178
  - `-t`, `--test`: Run tests using `pytest`.
176
179
  - `-a`, `--all`: Run with `-x -t -p <micro|minor|major> -c` development options.
@@ -208,6 +211,11 @@ runner.process(MyOptions())
208
211
  python -m crackerjack -u
209
212
  ```
210
213
 
214
+ - **Create a pull request to the upstream repository:**
215
+ ```
216
+ python -m crackerjack -r
217
+ ```
218
+
211
219
  - **Get help:**
212
220
  ```
213
221
  python -m crackerjack --help
@@ -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"
@@ -169,7 +169,7 @@ pythonPlatform = "Darwin"
169
169
 
170
170
  [project]
171
171
  name = "crackerjack"
172
- version = "0.15.10"
172
+ version = "0.16.0"
173
173
  description = "Default template for PDM package"
174
174
  requires-python = ">=3.13"
175
175
  readme = "README.md"
@@ -39,6 +39,7 @@ class OptionsForTesting:
39
39
  test: bool = False
40
40
  all: BumpOption | None = None
41
41
  ai_agent: bool = False
42
+ create_pr: bool = False
42
43
 
43
44
 
44
45
  @pytest.fixture
@@ -23,6 +23,7 @@ class MockOptions:
23
23
  self.bump = kwargs.get("bump")
24
24
  self.all = kwargs.get("all")
25
25
  self.ai_agent = kwargs.get("ai_agent", False)
26
+ self.create_pr = kwargs.get("create_pr", False)
26
27
 
27
28
 
28
29
  def test_create_crackerjack_runner() -> None:
@@ -36,6 +36,7 @@ def test_no_options(runner: CliRunner, mock_crackerjack_process: MagicMock) -> N
36
36
  assert not options.verbose
37
37
  assert not options.clean
38
38
  assert not options.test
39
+ assert not options.create_pr
39
40
 
40
41
 
41
42
  def test_commit_option(runner: CliRunner, mock_crackerjack_process: MagicMock) -> None:
@@ -221,6 +222,7 @@ def test_create_options() -> None:
221
222
  clean=True,
222
223
  test=True,
223
224
  all=BumpOption.minor,
225
+ create_pr=True,
224
226
  )
225
227
  assert test_options.commit
226
228
  assert test_options.interactive
@@ -233,6 +235,7 @@ def test_create_options() -> None:
233
235
  assert test_options.clean
234
236
  assert test_options.test
235
237
  assert test_options.all == BumpOption.minor
238
+ assert test_options.create_pr
236
239
 
237
240
 
238
241
  def test_conflicting_options(
@@ -278,3 +281,18 @@ def test_all_option_with_other_options(
278
281
  assert options.all == BumpOption.micro
279
282
  assert options.commit
280
283
  assert options.test
284
+
285
+
286
+ def test_create_pr_option(
287
+ runner: CliRunner, mock_crackerjack_process: MagicMock
288
+ ) -> None:
289
+ result = runner.invoke(app, ["-r"])
290
+ assert result.exit_code == 0
291
+ mock_crackerjack_process.process.assert_called_once()
292
+ options = mock_crackerjack_process.process.call_args[0][0]
293
+ assert options.create_pr
294
+ mock_crackerjack_process.process.reset_mock()
295
+ result = runner.invoke(app, ["--pr"])
296
+ assert result.exit_code == 0
297
+ options = mock_crackerjack_process.process.call_args[0][0]
298
+ assert options.create_pr
File without changes