git-copilot-commit 0.4.5__tar.gz → 0.4.6__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_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/PKG-INFO +2 -1
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/pyproject.toml +1 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/src/git_copilot_commit/cli.py +75 -5
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/src/git_copilot_commit/github_copilot.py +77 -19
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/uv.lock +11 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/.github/workflows/ci.yml +0 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/.gitignore +0 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/.justfile +0 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/.python-version +0 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/LICENSE +0 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/README.md +0 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/src/git_copilot_commit/__init__.py +0 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/src/git_copilot_commit/git.py +0 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/src/git_copilot_commit/prompts/commit-message-generator-prompt.md +0 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/src/git_copilot_commit/py.typed +0 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/src/git_copilot_commit/settings.py +0 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/src/git_copilot_commit/version.py +0 -0
- {git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/vhs/demo.vhs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-copilot-commit
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.6
|
|
4
4
|
Summary: Automatically generate and commit changes using copilot
|
|
5
5
|
Author-email: Dheepak Krishnamurthy <1813121+kdheepak@users.noreply.github.com>
|
|
6
6
|
License-File: LICENSE
|
|
@@ -8,6 +8,7 @@ Requires-Python: >=3.12
|
|
|
8
8
|
Requires-Dist: httpx>=0.28.0
|
|
9
9
|
Requires-Dist: platformdirs>=4.0.0
|
|
10
10
|
Requires-Dist: rich>=14.0.0
|
|
11
|
+
Requires-Dist: truststore>=0.10.4
|
|
11
12
|
Requires-Dist: typer>=0.16.0
|
|
12
13
|
Description-Content-Type: text/markdown
|
|
13
14
|
|
|
@@ -3,6 +3,7 @@ git-copilot-commit - AI-powered Git commit assistant
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from pathlib import Path
|
|
6
|
+
from typing import Annotated
|
|
6
7
|
|
|
7
8
|
import rich
|
|
8
9
|
import typer
|
|
@@ -18,6 +19,27 @@ from . import github_copilot
|
|
|
18
19
|
console = Console()
|
|
19
20
|
app = typer.Typer(help=__doc__, add_completion=False)
|
|
20
21
|
|
|
22
|
+
CA_BUNDLE_HELP = (
|
|
23
|
+
"Path to a custom CA bundle (PEM). Use this to test internal / company CAs."
|
|
24
|
+
)
|
|
25
|
+
NATIVE_TLS_HELP = (
|
|
26
|
+
"Use the OS's native certificate store via 'truststore' for httpx instead of "
|
|
27
|
+
"the Python bundle. Ignored if --ca-bundle or --insecure is used."
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
CaBundleOption = Annotated[
|
|
31
|
+
str | None,
|
|
32
|
+
typer.Option("--ca-bundle", metavar="PATH", help=CA_BUNDLE_HELP),
|
|
33
|
+
]
|
|
34
|
+
InsecureOption = Annotated[
|
|
35
|
+
bool,
|
|
36
|
+
typer.Option("--insecure", help="Disable SSL certificate verification."),
|
|
37
|
+
]
|
|
38
|
+
NativeTlsOption = Annotated[
|
|
39
|
+
bool,
|
|
40
|
+
typer.Option("--native-tls/--no-native-tls", help=NATIVE_TLS_HELP),
|
|
41
|
+
]
|
|
42
|
+
|
|
21
43
|
|
|
22
44
|
def version_callback(value: bool):
|
|
23
45
|
if value:
|
|
@@ -84,8 +106,24 @@ def load_system_prompt() -> str:
|
|
|
84
106
|
raise typer.Exit(1)
|
|
85
107
|
|
|
86
108
|
|
|
109
|
+
def build_http_client_config(
|
|
110
|
+
*,
|
|
111
|
+
ca_bundle: str | None,
|
|
112
|
+
insecure: bool,
|
|
113
|
+
native_tls: bool,
|
|
114
|
+
) -> github_copilot.HttpClientConfig:
|
|
115
|
+
return github_copilot.HttpClientConfig(
|
|
116
|
+
native_tls=native_tls,
|
|
117
|
+
insecure=insecure,
|
|
118
|
+
ca_bundle=ca_bundle,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
87
122
|
def generate_commit_message(
|
|
88
|
-
repo: GitRepository,
|
|
123
|
+
repo: GitRepository,
|
|
124
|
+
model: str | None = None,
|
|
125
|
+
context: str = "",
|
|
126
|
+
http_client_config: github_copilot.HttpClientConfig | None = None,
|
|
89
127
|
) -> str:
|
|
90
128
|
"""Generate a conventional commit message using Copilot API."""
|
|
91
129
|
|
|
@@ -127,6 +165,7 @@ def generate_commit_message(
|
|
|
127
165
|
{prompt}
|
|
128
166
|
""",
|
|
129
167
|
model=model,
|
|
168
|
+
http_client_config=http_client_config,
|
|
130
169
|
)
|
|
131
170
|
|
|
132
171
|
|
|
@@ -157,10 +196,21 @@ def authenticate(
|
|
|
157
196
|
force: bool = typer.Option(
|
|
158
197
|
False, "--force", help="Replace cached GitHub Copilot credentials"
|
|
159
198
|
),
|
|
199
|
+
ca_bundle: CaBundleOption = None,
|
|
200
|
+
insecure: InsecureOption = False,
|
|
201
|
+
native_tls: NativeTlsOption = False,
|
|
160
202
|
):
|
|
161
203
|
"""Authenticate with GitHub Copilot and cache credentials locally."""
|
|
204
|
+
http_client_config = build_http_client_config(
|
|
205
|
+
ca_bundle=ca_bundle,
|
|
206
|
+
insecure=insecure,
|
|
207
|
+
native_tls=native_tls,
|
|
208
|
+
)
|
|
162
209
|
try:
|
|
163
|
-
github_copilot.login(
|
|
210
|
+
github_copilot.login(
|
|
211
|
+
force=force,
|
|
212
|
+
http_client_config=http_client_config,
|
|
213
|
+
)
|
|
164
214
|
except github_copilot.CopilotError as exc:
|
|
165
215
|
console.print(f"[red]Authentication failed: {exc}[/red]")
|
|
166
216
|
raise typer.Exit(1)
|
|
@@ -183,6 +233,9 @@ def commit(
|
|
|
183
233
|
"-c",
|
|
184
234
|
help="Optional user-provided context to guide commit message",
|
|
185
235
|
),
|
|
236
|
+
ca_bundle: CaBundleOption = None,
|
|
237
|
+
insecure: InsecureOption = False,
|
|
238
|
+
native_tls: NativeTlsOption = False,
|
|
186
239
|
):
|
|
187
240
|
"""
|
|
188
241
|
Generate commit message based on changes in the current git repository and commit them.
|
|
@@ -198,9 +251,18 @@ def commit(
|
|
|
198
251
|
except github_copilot.CopilotError:
|
|
199
252
|
existing_credentials = None
|
|
200
253
|
|
|
254
|
+
http_client_config = build_http_client_config(
|
|
255
|
+
ca_bundle=ca_bundle,
|
|
256
|
+
insecure=insecure,
|
|
257
|
+
native_tls=native_tls,
|
|
258
|
+
)
|
|
259
|
+
|
|
201
260
|
if existing_credentials is None:
|
|
202
261
|
try:
|
|
203
|
-
github_copilot.login(
|
|
262
|
+
github_copilot.login(
|
|
263
|
+
force=True,
|
|
264
|
+
http_client_config=http_client_config,
|
|
265
|
+
)
|
|
204
266
|
except github_copilot.CopilotError as exc:
|
|
205
267
|
console.print(f"[red]Authentication failed: {exc}[/red]")
|
|
206
268
|
raise typer.Exit(1)
|
|
@@ -248,13 +310,21 @@ def commit(
|
|
|
248
310
|
)
|
|
249
311
|
|
|
250
312
|
try:
|
|
251
|
-
github_copilot.ensure_auth_ready(
|
|
313
|
+
github_copilot.ensure_auth_ready(
|
|
314
|
+
model=model,
|
|
315
|
+
http_client_config=http_client_config,
|
|
316
|
+
)
|
|
252
317
|
|
|
253
318
|
# Generate or use provided commit message
|
|
254
319
|
with console.status(
|
|
255
320
|
"[yellow]Generating commit message based on [bold]`git diff --staged`[/] ...[/yellow]"
|
|
256
321
|
):
|
|
257
|
-
commit_message = generate_commit_message(
|
|
322
|
+
commit_message = generate_commit_message(
|
|
323
|
+
repo,
|
|
324
|
+
model,
|
|
325
|
+
context=context,
|
|
326
|
+
http_client_config=http_client_config,
|
|
327
|
+
)
|
|
258
328
|
except github_copilot.CopilotError as exc:
|
|
259
329
|
console.print(f"[red]Could not generate a commit message: {exc}[/red]")
|
|
260
330
|
raise typer.Exit(1)
|
{git_copilot_commit-0.4.5 → git_copilot_commit-0.4.6}/src/git_copilot_commit/github_copilot.py
RENAMED
|
@@ -13,7 +13,6 @@ from pathlib import Path
|
|
|
13
13
|
from typing import Any, Callable, TypeVar
|
|
14
14
|
|
|
15
15
|
import httpx
|
|
16
|
-
import typer
|
|
17
16
|
from rich.console import Console
|
|
18
17
|
from rich.panel import Panel
|
|
19
18
|
from rich.table import Table
|
|
@@ -42,14 +41,7 @@ DEFAULT_MODEL_PREFERENCES = (
|
|
|
42
41
|
"gpt-4o",
|
|
43
42
|
)
|
|
44
43
|
|
|
45
|
-
app = typer.Typer(
|
|
46
|
-
add_completion=False,
|
|
47
|
-
no_args_is_help=True,
|
|
48
|
-
help="General-purpose GitHub Copilot CLI.",
|
|
49
|
-
)
|
|
50
|
-
|
|
51
44
|
console = Console()
|
|
52
|
-
console_err = Console(stderr=True)
|
|
53
45
|
T = TypeVar("T")
|
|
54
46
|
|
|
55
47
|
|
|
@@ -164,6 +156,25 @@ class CopilotModel:
|
|
|
164
156
|
)
|
|
165
157
|
|
|
166
158
|
|
|
159
|
+
@dataclass(frozen=True, slots=True)
|
|
160
|
+
class HttpClientConfig:
|
|
161
|
+
native_tls: bool = False
|
|
162
|
+
insecure: bool = False
|
|
163
|
+
ca_bundle: str | None = None
|
|
164
|
+
|
|
165
|
+
@property
|
|
166
|
+
def use_native_tls(self) -> bool:
|
|
167
|
+
return self.native_tls and not self.insecure and self.ca_bundle is None
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def verify(self) -> bool | str:
|
|
171
|
+
if self.insecure:
|
|
172
|
+
return False
|
|
173
|
+
if self.ca_bundle:
|
|
174
|
+
return self.ca_bundle
|
|
175
|
+
return True
|
|
176
|
+
|
|
177
|
+
|
|
167
178
|
@dataclass(slots=True)
|
|
168
179
|
class GitHubViewer:
|
|
169
180
|
login: str
|
|
@@ -272,8 +283,34 @@ def get_github_copilot_base_url(
|
|
|
272
283
|
return "https://api.individual.githubcopilot.com"
|
|
273
284
|
|
|
274
285
|
|
|
275
|
-
|
|
286
|
+
_NATIVE_TLS_ENABLED = False
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _maybe_enable_native_tls(native_tls: bool) -> None:
|
|
290
|
+
"""
|
|
291
|
+
Globally switch httpx/requests to use the OS certificate store via truststore.
|
|
292
|
+
Safe to call multiple times; it no-ops after the first.
|
|
293
|
+
"""
|
|
294
|
+
global _NATIVE_TLS_ENABLED
|
|
295
|
+
if not native_tls or _NATIVE_TLS_ENABLED:
|
|
296
|
+
return
|
|
297
|
+
|
|
298
|
+
try:
|
|
299
|
+
import truststore
|
|
300
|
+
|
|
301
|
+
truststore.inject_into_ssl()
|
|
302
|
+
except Exception as _:
|
|
303
|
+
return
|
|
304
|
+
|
|
305
|
+
_NATIVE_TLS_ENABLED = True
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def make_http_client(http_client_config: HttpClientConfig | None = None) -> httpx.Client:
|
|
309
|
+
config = http_client_config or HttpClientConfig()
|
|
310
|
+
_maybe_enable_native_tls(config.use_native_tls)
|
|
311
|
+
|
|
276
312
|
return httpx.Client(
|
|
313
|
+
verify=config.verify,
|
|
277
314
|
follow_redirects=True,
|
|
278
315
|
timeout=httpx.Timeout(30.0, connect=10.0),
|
|
279
316
|
)
|
|
@@ -1140,7 +1177,12 @@ def print_login_summary(
|
|
|
1140
1177
|
console.print(Panel.fit(table, title="Login Summary"))
|
|
1141
1178
|
|
|
1142
1179
|
|
|
1143
|
-
def login(
|
|
1180
|
+
def login(
|
|
1181
|
+
enterprise_domain: str | None = None,
|
|
1182
|
+
force: bool = False,
|
|
1183
|
+
*,
|
|
1184
|
+
http_client_config: HttpClientConfig | None = None,
|
|
1185
|
+
) -> None:
|
|
1144
1186
|
"""Authenticate with GitHub and cache Copilot credentials locally."""
|
|
1145
1187
|
normalized_domain = normalize_domain(enterprise_domain)
|
|
1146
1188
|
if enterprise_domain and not normalized_domain:
|
|
@@ -1159,7 +1201,7 @@ def login(enterprise_domain: str | None = None, force: bool = False) -> None:
|
|
|
1159
1201
|
)
|
|
1160
1202
|
|
|
1161
1203
|
domain = normalized_domain or DEFAULT_GITHUB_DOMAIN
|
|
1162
|
-
with make_http_client() as client:
|
|
1204
|
+
with make_http_client(http_client_config) as client:
|
|
1163
1205
|
device = start_device_flow(client, domain)
|
|
1164
1206
|
|
|
1165
1207
|
console.print(
|
|
@@ -1220,9 +1262,13 @@ def _ask_once(client: httpx.Client, prompt: str, model: str | None = None) -> st
|
|
|
1220
1262
|
)
|
|
1221
1263
|
|
|
1222
1264
|
|
|
1223
|
-
def _with_reauthentication(
|
|
1265
|
+
def _with_reauthentication(
|
|
1266
|
+
action: Callable[[httpx.Client], T],
|
|
1267
|
+
*,
|
|
1268
|
+
http_client_config: HttpClientConfig | None = None,
|
|
1269
|
+
) -> T:
|
|
1224
1270
|
try:
|
|
1225
|
-
with make_http_client() as client:
|
|
1271
|
+
with make_http_client(http_client_config) as client:
|
|
1226
1272
|
return action(client)
|
|
1227
1273
|
except CopilotError as exc:
|
|
1228
1274
|
if not should_reauthenticate(exc):
|
|
@@ -1231,21 +1277,33 @@ def _with_reauthentication(action: Callable[[httpx.Client], T]) -> T:
|
|
|
1231
1277
|
console.print(
|
|
1232
1278
|
"[yellow]Cached GitHub Copilot credentials are missing or no longer valid. Starting authentication...[/yellow]"
|
|
1233
1279
|
)
|
|
1234
|
-
login(force=True)
|
|
1280
|
+
login(force=True, http_client_config=http_client_config)
|
|
1235
1281
|
|
|
1236
|
-
with make_http_client() as client:
|
|
1282
|
+
with make_http_client(http_client_config) as client:
|
|
1237
1283
|
return action(client)
|
|
1238
1284
|
|
|
1239
1285
|
|
|
1240
|
-
def ensure_auth_ready(
|
|
1286
|
+
def ensure_auth_ready(
|
|
1287
|
+
model: str | None = None,
|
|
1288
|
+
*,
|
|
1289
|
+
http_client_config: HttpClientConfig | None = None,
|
|
1290
|
+
) -> None:
|
|
1241
1291
|
def validate(client: httpx.Client) -> None:
|
|
1242
1292
|
credentials = ensure_fresh_credentials(client)
|
|
1243
1293
|
all_models = list_models(client, credentials)
|
|
1244
1294
|
pick_model(all_models, model)
|
|
1245
1295
|
|
|
1246
|
-
_with_reauthentication(validate)
|
|
1296
|
+
_with_reauthentication(validate, http_client_config=http_client_config)
|
|
1247
1297
|
|
|
1248
1298
|
|
|
1249
|
-
def ask(
|
|
1299
|
+
def ask(
|
|
1300
|
+
prompt: str,
|
|
1301
|
+
model: str | None = None,
|
|
1302
|
+
*,
|
|
1303
|
+
http_client_config: HttpClientConfig | None = None,
|
|
1304
|
+
) -> str:
|
|
1250
1305
|
"""Send a prompt to GitHub Copilot and print the reply."""
|
|
1251
|
-
return _with_reauthentication(
|
|
1306
|
+
return _with_reauthentication(
|
|
1307
|
+
lambda client: _ask_once(client, prompt, model),
|
|
1308
|
+
http_client_config=http_client_config,
|
|
1309
|
+
)
|
|
@@ -53,6 +53,7 @@ dependencies = [
|
|
|
53
53
|
{ name = "httpx" },
|
|
54
54
|
{ name = "platformdirs" },
|
|
55
55
|
{ name = "rich" },
|
|
56
|
+
{ name = "truststore" },
|
|
56
57
|
{ name = "typer" },
|
|
57
58
|
]
|
|
58
59
|
|
|
@@ -61,6 +62,7 @@ requires-dist = [
|
|
|
61
62
|
{ name = "httpx", specifier = ">=0.28.0" },
|
|
62
63
|
{ name = "platformdirs", specifier = ">=4.0.0" },
|
|
63
64
|
{ name = "rich", specifier = ">=14.0.0" },
|
|
65
|
+
{ name = "truststore", specifier = ">=0.10.4" },
|
|
64
66
|
{ name = "typer", specifier = ">=0.16.0" },
|
|
65
67
|
]
|
|
66
68
|
|
|
@@ -180,6 +182,15 @@ wheels = [
|
|
|
180
182
|
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
|
181
183
|
]
|
|
182
184
|
|
|
185
|
+
[[package]]
|
|
186
|
+
name = "truststore"
|
|
187
|
+
version = "0.10.4"
|
|
188
|
+
source = { registry = "https://pypi.org/simple" }
|
|
189
|
+
sdist = { url = "https://files.pythonhosted.org/packages/53/a3/1585216310e344e8102c22482f6060c7a6ea0322b63e026372e6dcefcfd6/truststore-0.10.4.tar.gz", hash = "sha256:9d91bd436463ad5e4ee4aba766628dd6cd7010cf3e2461756b3303710eebc301", size = 26169, upload-time = "2025-08-12T18:49:02.73Z" }
|
|
190
|
+
wheels = [
|
|
191
|
+
{ url = "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl", hash = "sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981", size = 18660, upload-time = "2025-08-12T18:49:01.46Z" },
|
|
192
|
+
]
|
|
193
|
+
|
|
183
194
|
[[package]]
|
|
184
195
|
name = "typer"
|
|
185
196
|
version = "0.16.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|