Skip to content

Commit 48bbceb

Browse files
committed
feat: add GitHub Actions workflow for PyPI publishing
chore: update dependencies and version in pyproject.toml refactor: centralize config management and add environment variable fallback fix: update imports and API key retrieval across multiple files
1 parent 0531c2b commit 48bbceb

File tree

12 files changed

+124
-62
lines changed

12 files changed

+124
-62
lines changed

.github/workflows/publish.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Publish to PyPI
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*' # Trigger on version tags
7+
8+
jobs:
9+
publish:
10+
runs-on: ubuntu-latest
11+
permissions:
12+
contents: write # Needed for creating releases
13+
steps:
14+
- uses: actions/checkout@v4
15+
with:
16+
fetch-depth: 0 # Fetch all history for changelog generation
17+
18+
- name: Set up Python
19+
uses: actions/setup-python@v5
20+
with:
21+
python-version: "3.x"
22+
23+
- name: Extract version from tag
24+
id: get_version
25+
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
26+
27+
- name: Update version in files
28+
run: |
29+
# Update __init__.py
30+
echo "__version__ = \"$VERSION\"" > src/wellcode_cli/__init__.py
31+
32+
# Update pyproject.toml
33+
sed -i "s/version = \".*\"/version = \"$VERSION\"/" pyproject.toml
34+
35+
- name: Install dependencies
36+
run: |
37+
python -m pip install --upgrade pip
38+
pip install build twine
39+
40+
- name: Build package
41+
run: python -m build
42+
43+
- name: Publish to PyPI
44+
env:
45+
TWINE_USERNAME: __token__
46+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
47+
run: |
48+
twine upload dist/*
49+
50+
- name: Create GitHub Release
51+
uses: softprops/action-gh-release@v1
52+
with:
53+
name: Release ${{ env.VERSION }}
54+
draft: false
55+
prerelease: false
56+
generate_release_notes: true

pyproject.toml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "wellcode-cli"
7-
version = "0.1.29"
7+
version = "0.1.31"
88
description = "Engineering Metrics Analysis Tool"
99
readme = "README.md"
1010
authors = [{ name = "Your Name", email = "your.email@example.com" }]
@@ -21,6 +21,15 @@ dependencies = [
2121
"chardet>=5.2.0",
2222
"idna>=3.6",
2323
"certifi>=2023.7.22",
24+
"rich>=13.0.0",
25+
"rich-click>=1.6.0",
26+
"anthropic>=0.18.0",
27+
"python-dateutil>=2.8.2",
28+
"splitio-client>=9.2.0",
29+
"pandas>=2.0.0",
30+
"plotly>=5.18.0",
31+
"python-dotenv>=1.0.0",
32+
"click>=8.0.0"
2433
]
2534
requires-python = ">=3.8"
2635

src/wellcode_cli/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.1.29"
1+
__version__ = "0.1.31"

src/wellcode_cli/commands/chat.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import rich_click as click
55

66
import anthropic
7-
from ..utils import load_config
7+
from ..config import get_anthropic_api_key
88
from rich.prompt import Prompt
99
console = Console()
1010
from .review import review
@@ -23,12 +23,11 @@ def chat(initial_question=None):
2323
data = get_latest_analysis()
2424

2525
# Load configuration
26-
config_data = load_config()
27-
if not config_data.get('ANTHROPIC_API_KEY'):
26+
if not get_anthropic_api_key():
2827
console.print("[red]Error: Anthropic API key not configured. Please run 'wellcode-cli config'[/]")
2928
return
3029

31-
client = anthropic.Client(api_key=config_data['ANTHROPIC_API_KEY'])
30+
client = anthropic.Client(api_key=get_anthropic_api_key())
3231

3332
console.print("[bold blue]Wellcode AI Chat[/]")
3433
console.print("Ask questions about your engineering metrics. Type 'exit' to quit.\n")

src/wellcode_cli/commands/chat_interface.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from .review import review
1616
from .report import report
1717
from .chat import chat
18-
18+
from ..config import get_anthropic_api_key
1919
console = Console()
2020
CONFIG_FILE = Path.home() / '.wellcode' / 'config.json'
2121

@@ -36,8 +36,8 @@ def chat_interface():
3636

3737
# Initialize Anthropic client if configured
3838
client = None
39-
if config_data.get('ANTHROPIC_API_KEY'):
40-
client = anthropic.Client(api_key=config_data['ANTHROPIC_API_KEY'])
39+
if get_anthropic_api_key():
40+
client = anthropic.Client(api_key=get_anthropic_api_key())
4141

4242
while True:
4343
try:

src/wellcode_cli/commands/config.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from rich.console import Console
55
from rich.prompt import Prompt, Confirm
66
from rich.panel import Panel
7-
7+
from ..config import get_github_token, get_github_org, get_linear_api_key, get_split_api_key, get_anthropic_api_key
88
console = Console()
99
CONFIG_FILE = Path.home() / '.wellcode' / 'config.json'
1010

@@ -29,12 +29,12 @@ def config():
2929
console.print("\n[bold blue]GitHub Configuration[/] (required)")
3030
config_data['GITHUB_TOKEN'] = Prompt.ask(
3131
"Enter your GitHub token",
32-
default=config_data.get('GITHUB_TOKEN', ''),
32+
default=get_github_token(),
3333
password=True
3434
)
3535
config_data['GITHUB_ORG'] = Prompt.ask(
3636
"Enter your GitHub organization",
37-
default=config_data.get('GITHUB_ORG', '')
37+
default=get_github_org()
3838
)
3939

4040
# Linear configuration
@@ -43,7 +43,7 @@ def config():
4343
default=bool(config_data.get('LINEAR_API_KEY'))):
4444
config_data['LINEAR_API_KEY'] = Prompt.ask(
4545
"Enter your Linear API key",
46-
default=config_data.get('LINEAR_API_KEY', ''),
46+
default=get_linear_api_key(),
4747
password=True
4848
)
4949
console.print("[green]✓ Linear integration enabled[/]")
@@ -58,7 +58,7 @@ def config():
5858
default=bool(config_data.get('SPLIT_API_KEY'))):
5959
config_data['SPLIT_API_KEY'] = Prompt.ask(
6060
"Enter your Split.io API key",
61-
default=config_data.get('SPLIT_API_KEY', ''),
61+
default=get_split_api_key(),
6262
password=True
6363
)
6464
console.print("[green]✓ Split.io integration enabled[/]")
@@ -73,7 +73,7 @@ def config():
7373
default=bool(config_data.get('ANTHROPIC_API_KEY'))):
7474
config_data['ANTHROPIC_API_KEY'] = Prompt.ask(
7575
"Enter your Anthropic API key",
76-
default=config_data.get('ANTHROPIC_API_KEY', ''),
76+
default=get_anthropic_api_key(),
7777
password=True
7878
)
7979
console.print("[green]✓ AI-powered insights enabled[/]")

src/wellcode_cli/commands/review.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from ..split_metrics import get_split_metrics, display_split_metrics
1313
from ..utils import save_analysis_data
1414
from .config import config
15+
from ..config import get_github_token, get_github_org, get_linear_api_key, get_split_api_key, get_anthropic_api_key
1516
from ..utils import load_config
1617
from anthropic import InternalServerError, APIError, RateLimitError
1718
console = Console()
@@ -65,16 +66,16 @@ def review(start_date, end_date, user, team):
6566

6667
with console.status("[bold green]Fetching metrics...") as status:
6768
# GitHub metrics
68-
if config_data.get('GITHUB_TOKEN'):
69+
if get_github_token():
6970
status.update("Fetching GitHub metrics...")
70-
metrics = get_github_metrics(config_data['GITHUB_ORG'], start_date, end_date, user, team)
71+
metrics = get_github_metrics(get_github_org(), start_date, end_date, user, team)
7172
all_metrics['github'] = metrics
7273
display_github_metrics(metrics)
7374
else:
7475
console.print("[yellow]⚠️ GitHub integration not configured[/]")
7576

7677
# Linear metrics
77-
if config_data.get('LINEAR_API_KEY'):
78+
if get_linear_api_key():
7879
status.update("Fetching Linear metrics...")
7980
linear_metrics = get_linear_metrics(start_date, end_date, user)
8081
all_metrics['linear'] = linear_metrics
@@ -83,7 +84,7 @@ def review(start_date, end_date, user, team):
8384
console.print("[yellow]⚠️ Linear integration not configured[/]")
8485

8586
# Split metrics
86-
if config_data.get('SPLIT_API_KEY'):
87+
if get_split_api_key():
8788
status.update("Fetching Split metrics...")
8889
split_metrics = get_split_metrics(start_date, end_date)
8990
all_metrics['split'] = split_metrics
@@ -92,7 +93,7 @@ def review(start_date, end_date, user, team):
9293
console.print("[yellow]⚠️ Split.io integration not configured[/]")
9394

9495
# AI Analysis
95-
if config_data.get('ANTHROPIC_API_KEY'):
96+
if get_anthropic_api_key():
9697
try:
9798
status.update("Generating AI analysis...")
9899
analysis_result = get_ai_analysis(all_metrics)

src/wellcode_cli/config.py

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,41 @@
1-
import os
21
from pathlib import Path
32
import json
4-
from dotenv import load_dotenv
3+
import os
4+
from typing import Optional
5+
from rich.console import Console
56

6-
# Load environment variables from .env file
7-
load_dotenv()
7+
console = Console()
88

9-
# Define config file location
109
CONFIG_DIR = Path.home() / '.wellcode'
1110
CONFIG_FILE = CONFIG_DIR / 'config.json'
1211

13-
# Load configuration from file
14-
config_data = {}
15-
if CONFIG_FILE.exists():
16-
with open(CONFIG_FILE) as f:
17-
config_data = json.load(f)
12+
def get_config_value(key: str) -> Optional[str]:
13+
"""Get configuration value with fallback to environment variables"""
14+
# First try to load from config file
15+
if CONFIG_FILE.exists():
16+
try:
17+
with open(CONFIG_FILE) as f:
18+
config_data = json.load(f)
19+
if key in config_data and config_data[key]:
20+
return config_data[key]
21+
except Exception as e:
22+
console.print(f"[yellow]Warning: Error reading config file: {e}[/]")
23+
24+
# Fallback to environment variable
25+
return os.getenv(key)
26+
27+
# Export commonly used config values
28+
def get_github_token() -> Optional[str]:
29+
return get_config_value('GITHUB_TOKEN')
1830

19-
# GitHub configuration
20-
GITHUB_ORG = config_data.get('GITHUB_ORG') or os.getenv('GITHUB_ORG')
21-
GITHUB_TOKEN = config_data.get('GITHUB_TOKEN') or os.getenv('GITHUB_TOKEN')
31+
def get_github_org() -> Optional[str]:
32+
return get_config_value('GITHUB_ORG')
2233

23-
# Linear configuration
24-
LINEAR_API_KEY = config_data.get('LINEAR_API_KEY') or os.getenv('LINEAR_API_KEY')
34+
def get_linear_api_key() -> Optional[str]:
35+
return get_config_value('LINEAR_API_KEY')
2536

26-
# Anthropic configuration
27-
ANTHROPIC_API_KEY = config_data.get('ANTHROPIC_API_KEY') or os.getenv('ANTHROPIC_API_KEY')
37+
def get_anthropic_api_key() -> Optional[str]:
38+
return get_config_value('ANTHROPIC_API_KEY')
2839

29-
# Split.io configuration
30-
SPLIT_API_KEY = config_data.get('SPLIT_API_KEY') or os.getenv('SPLIT_API_KEY')
40+
def get_split_api_key() -> Optional[str]:
41+
return get_config_value('SPLIT_API_KEY')

src/wellcode_cli/github/github_format_ai.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,10 @@
55
from anthropic import Anthropic
66
from .models.metrics import MetricsJSONEncoder
77
import json
8-
try:
9-
from ..config import ANTHROPIC_API_KEY
10-
except ImportError:
11-
raise ImportError("Failed to import configuration. Ensure config.py exists and is properly set up.")
12-
8+
from ..config import get_anthropic_api_key
139
client = Anthropic(
1410
# This is the default and can be omitted
15-
api_key=ANTHROPIC_API_KEY,
11+
api_key=get_anthropic_api_key(),
1612
)
1713
console = Console()
1814

src/wellcode_cli/github/github_metrics.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@
77
from .models.metrics import (
88
OrganizationMetrics, RepositoryMetrics
99
)
10-
from ..config import GITHUB_TOKEN
1110
from .utils import ensure_datetime
12-
11+
from ..config import get_github_token
1312
console = Console()
1413

1514
def get_github_metrics(org_name: str, start_date, end_date, user_filter=None, team_filter=None) -> OrganizationMetrics:
1615
"""Main function to get GitHub metrics for an organization"""
17-
g = Github(GITHUB_TOKEN)
16+
g = Github(get_github_token())
1817
org = g.get_organization(org_name)
1918

2019
# Ensure start_date and end_date are timezone-aware

0 commit comments

Comments
 (0)