Skip to content

Commit a4d76fc

Browse files
committed
merge: bring private changes to dev
Latest changes from main including .flake8 configuration and all repokit module updates with fixes for adopt command, auth integration, and improved error handling.
2 parents fc6eaf2 + 6c6ab6b commit a4d76fc

10 files changed

Lines changed: 1950 additions & 1484 deletions

.flake8

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
[flake8]
2+
# Treat most style issues as warnings rather than errors
3+
# This prevents CI/CD from failing on style issues while still showing them
4+
5+
# Maximum line length (slightly more lenient than default)
6+
max-line-length = 88
7+
8+
# Treat these as warnings instead of errors
9+
# E501: line too long
10+
# F401: imported but unused
11+
# F541: f-string is missing placeholders
12+
# W293: blank line contains whitespace
13+
# W291: trailing whitespace
14+
# E128: continuation line under-indented for visual indent
15+
# E302: expected 2 blank lines, found 1
16+
warn-symbols = E501,F401,F541,W293,W291,E128,E302
17+
18+
# Only treat serious issues as errors
19+
select = E9,F63,F7,F82
20+
21+
# Ignore the following (treat as warnings or ignore completely)
22+
ignore =
23+
# Line length (we set max-line-length above)
24+
E501,
25+
# Whitespace issues (cosmetic)
26+
W291,W293,
27+
# Import issues (non-critical)
28+
F401,
29+
# f-string issues (minor)
30+
F541,
31+
# Indentation issues (cosmetic)
32+
E128,
33+
# Blank line issues (cosmetic)
34+
E302
35+
36+
# Files to exclude from checking
37+
exclude =
38+
.git,
39+
__pycache__,
40+
*.pyc,
41+
.venv,
42+
venv,
43+
.tox,
44+
dist,
45+
build,
46+
*.egg-info,
47+
private/,
48+
test_runs/,
49+
revisions/old_*,
50+
**/repo-manager-worktree-fix.py
51+
52+
# Show statistics
53+
statistics = True
54+
count = True

repokit/auth_integration.py

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,36 @@
1212
from pathlib import Path
1313
from typing import Dict, Any, Optional, Tuple
1414

15+
1516
class AuthenticationHandler:
1617
"""
1718
Handles authentication with remote services.
1819
"""
19-
20+
2021
def __init__(self, verbose: int = 0):
2122
"""
2223
Initialize the authentication handler.
23-
24+
2425
Args:
2526
verbose: Verbosity level (0=normal, 1=info, 2=debug)
2627
"""
2728
self.verbose = verbose
2829
self.logger = logging.getLogger("repokit.auth")
29-
30+
3031
# Default locations for credentials
3132
self.user_home = Path.home()
3233
self.default_creds_path = self.user_home / ".repokit" / "credentials.json"
33-
34+
3435
# Initialize with empty credentials
3536
self.credentials = {}
36-
37+
3738
def load_credentials(self, credentials_file: Optional[str] = None) -> bool:
3839
"""
3940
Load credentials from a file.
40-
41+
4142
Args:
4243
credentials_file: Path to credentials file (or None to use default)
43-
44+
4445
Returns:
4546
True if loaded successfully, False otherwise
4647
"""
@@ -52,48 +53,50 @@ def load_credentials(self, credentials_file: Optional[str] = None) -> bool:
5253
if self.verbose >= 1:
5354
self.logger.info("No credentials file found")
5455
return False
55-
56+
5657
try:
57-
with open(creds_path, 'r') as f:
58+
with open(creds_path, "r") as f:
5859
self.credentials = json.load(f)
59-
60+
6061
if self.verbose >= 1:
6162
self.logger.info(f"Loaded credentials from {creds_path}")
6263
return True
6364
except Exception as e:
6465
self.logger.error(f"Error loading credentials: {str(e)}")
6566
return False
66-
67-
def get_token(self, service: str, token_command: Optional[str] = None) -> Optional[str]:
67+
68+
def get_token(
69+
self, service: str, token_command: Optional[str] = None
70+
) -> Optional[str]:
6871
"""
6972
Get authentication token for a service.
70-
73+
7174
Tries multiple sources in this order:
7275
1. Command provided token command
7376
2. Environment variable
7477
3. Credentials file
75-
78+
7679
Args:
7780
service: Service name ('github' or 'gitlab')
7881
token_command: Optional command to retrieve token from password manager
79-
82+
8083
Returns:
8184
Authentication token or None if not found
8285
"""
8386
# Standardize service name
8487
service = service.lower()
85-
88+
8689
# 1. Try token command if provided
8790
if token_command:
8891
try:
8992
if self.verbose >= 2:
9093
self.logger.debug(f"Running token command: {token_command}")
9194
result = subprocess.run(
92-
token_command,
93-
shell=True,
95+
token_command,
96+
shell=True,
9497
check=True,
9598
capture_output=True,
96-
text=True
99+
text=True,
97100
)
98101
token = result.stdout.strip()
99102
if token:
@@ -102,63 +105,63 @@ def get_token(self, service: str, token_command: Optional[str] = None) -> Option
102105
return token
103106
except Exception as e:
104107
self.logger.error(f"Failed to get token from command: {str(e)}")
105-
108+
106109
# 2. Try environment variable
107110
env_var = f"{service.upper()}_TOKEN"
108111
token = os.environ.get(env_var)
109112
if token:
110113
if self.verbose >= 1:
111114
self.logger.info(f"Using {service} token from environment variable")
112115
return token
113-
116+
114117
# 3. Try credentials file
115118
if service in self.credentials and "token" in self.credentials[service]:
116119
if self.verbose >= 1:
117120
self.logger.info(f"Using {service} token from credentials file")
118121
return self.credentials[service]["token"]
119-
122+
120123
# Token not found
121124
self.logger.warning(f"No {service} token found")
122125
return None
123-
126+
124127
def get_organization(self, service: str) -> Optional[str]:
125128
"""
126129
Get organization or group for a service.
127-
130+
128131
Args:
129132
service: Service name ('github' or 'gitlab')
130-
133+
131134
Returns:
132135
Organization/group name or None if not specified
133136
"""
134137
# Standardize service name
135138
service = service.lower()
136-
139+
137140
# Try environment variable first
138141
env_var = f"{service.upper()}_ORGANIZATION"
139142
if service == "gitlab":
140143
env_var = "GITLAB_GROUP" # GitLab uses "group" terminology
141-
144+
142145
org = os.environ.get(env_var)
143146
if org:
144147
return org
145-
148+
146149
# Try credentials file
147150
if service in self.credentials:
148151
if service == "github" and "organization" in self.credentials[service]:
149152
return self.credentials[service]["organization"]
150153
elif service == "gitlab" and "group" in self.credentials[service]:
151154
return self.credentials[service]["group"]
152-
155+
153156
return None
154-
157+
155158
def get_api_url(self, service: str) -> str:
156159
"""
157160
Get API URL for a service.
158-
161+
159162
Args:
160163
service: Service name ('github' or 'gitlab')
161-
164+
162165
Returns:
163166
API URL for the service
164167
"""
@@ -168,69 +171,73 @@ def get_api_url(self, service: str) -> str:
168171
return os.environ.get("GITLAB_API_URL", "https://gitlab.com/api/v4")
169172
else:
170173
return ""
171-
172-
def store_credentials(self, service: str, token: str,
173-
organization: Optional[str] = None,
174-
file_path: Optional[str] = None) -> bool:
174+
175+
def store_credentials(
176+
self,
177+
service: str,
178+
token: str,
179+
organization: Optional[str] = None,
180+
file_path: Optional[str] = None,
181+
) -> bool:
175182
"""
176183
Store credentials in the credentials file.
177-
184+
178185
Args:
179186
service: Service name ('github' or 'gitlab')
180187
token: Authentication token
181188
organization: Organization or group name (optional)
182189
file_path: Path to credentials file (or None to use default)
183-
190+
184191
Returns:
185192
True if stored successfully, False otherwise
186193
"""
187194
# Standardize service name
188195
service = service.lower()
189-
196+
190197
# Load existing credentials if file exists
191198
if file_path:
192199
creds_path = Path(file_path)
193200
else:
194201
creds_path = self.default_creds_path
195202
# Ensure directory exists
196203
creds_path.parent.mkdir(parents=True, exist_ok=True)
197-
204+
198205
# Load existing credentials if file exists
199206
existing_creds = {}
200207
if creds_path.exists():
201208
try:
202-
with open(creds_path, 'r') as f:
209+
with open(creds_path, "r") as f:
203210
existing_creds = json.load(f)
204211
except Exception as e:
205212
self.logger.error(f"Error loading existing credentials: {str(e)}")
206213
# Continue with empty credentials
207-
214+
208215
# Update credentials
209216
service_creds = existing_creds.get(service, {})
210217
service_creds["token"] = token
211-
218+
212219
if organization:
213220
if service == "github":
214221
service_creds["organization"] = organization
215222
elif service == "gitlab":
216223
service_creds["group"] = organization
217-
224+
218225
existing_creds[service] = service_creds
219-
226+
220227
# Save credentials
221228
try:
222-
with open(creds_path, 'w') as f:
229+
with open(creds_path, "w") as f:
223230
json.dump(existing_creds, f, indent=2)
224-
231+
225232
# Set restrictive permissions
226233
os.chmod(creds_path, 0o600)
227-
234+
228235
if self.verbose >= 1:
229236
self.logger.info(f"Stored {service} credentials in {creds_path}")
230-
237+
231238
# Update in-memory credentials
232239
self.credentials = existing_creds
233-
240+
234241
return True
235242
except Exception as e:
236243
self.logger.error(f"Error storing credentials: {str(e)}")

0 commit comments

Comments
 (0)