Skip to content
This repository was archived by the owner on Apr 23, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 21 additions & 18 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ name: Python CI

on:
push:
branches:
branches:
- "main"
tags: [ "v*" ] # Trigger on tags starting with v
pull_request:
Expand All @@ -33,7 +33,7 @@ jobs:
- uses: actions/checkout@v4
with:
# SonarCloud needs the full history to assign issues properly
fetch-depth: 0
fetch-depth: 0
# For PRs, fetch the base branch for comparison
ref: ${{ github.event.pull_request.head.sha }}

Expand All @@ -42,13 +42,16 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
shell: bash

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build pytest pytest-cov pytest-timeout ruff
pip install -e .
uv pip install --system build pytest pytest-cov pytest-timeout ruff
uv pip install --system -e .
# Show installed packages
pip list
uv pip list --system

- name: Check test directory structure
run: |
Expand Down Expand Up @@ -89,10 +92,10 @@ jobs:
# Set CI variables
export CI_TEST_TIMEOUT=120
export CI_EXIT_ON_TEST_FAILURE=1

# Run directly without using bash to make error handling clearer
bash -ex ./scripts/run_coverage_ci.sh || echo "Coverage generation had errors but we'll continue"

# Extract actual coverage percentage from XML file
if [ -f "coverage.xml" ]; then
COVERAGE=$(python -c "import xml.etree.ElementTree as ET; tree = ET.parse('coverage.xml'); root = tree.getroot(); line_rate = float(root.attrib['line-rate'])*100; print('{:.2f}%'.format(line_rate))")
Expand All @@ -109,17 +112,17 @@ jobs:
script: |
const coverage = process.env.COVERAGE_PERCENTAGE;
const pullRequestNumber = context.issue.number;

github.rest.issues.createComment({
issue_number: pullRequestNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## Code Coverage Report

📊 **Current Coverage:** ${coverage}

Detailed coverage analysis is available in [SonarCloud](https://sonarcloud.io/project/overview?id=BlueCentre_cli-code)

### Coverage Change Details
This shows code coverage for changes in this PR. To improve coverage, consider adding tests for new or modified code.`
});
Expand Down Expand Up @@ -173,14 +176,14 @@ jobs:

- name: Build package
run: python -m build

- name: Store built packages
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 7

- name: Upload coverage reports as artifacts
uses: actions/upload-artifact@v4
with:
Expand All @@ -191,7 +194,7 @@ jobs:
test_logs/
retention-days: 7
if-no-files-found: warn

publish:
name: Publish to PyPI
needs: build-and-test
Expand All @@ -202,14 +205,14 @@ jobs:
permissions:
id-token: write # Required for PyPI trusted publishing
contents: read # Required for actions/checkout

steps:
- name: Download built packages
uses: actions/download-artifact@v4
with:
name: dist
path: dist/

- name: Display packages to be published
run: |
echo "Packages to be published:"
Expand All @@ -230,4 +233,4 @@ jobs:
with:
password: ${{ secrets.PYPI_API_TOKEN }}
verbose: true
print-hash: true
print-hash: true
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,21 @@ For detailed installation instructions, please see the [Installation Guide](docs

**Recommended (PyPI):**
```bash
pip install cli-code-agent
uv pip install cli-code-agent

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The uv prefix is used here, but not consistently throughout the README and docs/install.md files. Should all pip commands use the uv prefix, or should it be removed entirely?

Suggested change
uv pip install cli-code-agent
pip install cli-code-agent

```

**From Source:**
```bash
git clone https://github.com/BlueCentre/cli-code.git
cd cli-code
pip install -e .
# Create a virtual environment (optional but recommended)
# uv venv
# source .venv/bin/activate

# Install in editable mode
uv pip install -e .
# For development including test dependencies, use:
# uv pip install -e '.[dev]'
Comment on lines +46 to +53

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The README instructs users to create a virtual environment but omits the activation step. Adding this would improve clarity. Also, the commented-out lines should be removed for better readability.

Suggested change
# Create a virtual environment (optional but recommended)
# uv venv
# source .venv/bin/activate
# Install in editable mode
uv pip install -e .
# For development including test dependencies, use:
# uv pip install -e '.[dev]'
git clone https://github.com/BlueCentre/cli-code.git
cd cli-code
uv venv
source .venv/bin/activate
uv pip install -e .
# For development including test dependencies, use:
uv pip install -e '.[dev]'

```

## Setup
Expand Down
13 changes: 10 additions & 3 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,22 @@ This guide explains how to install, configure, and use CLI-Code.
### Option 1: Install from PyPI (Recommended)

```bash
pip install cli-code-agent
uv pip install cli-code-agent

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The uv prefix is used here, but not consistently throughout the README and docs/install.md files. Should all pip commands use the uv prefix, or should it be removed entirely?

Suggested change
uv pip install cli-code-agent
pip install cli-code-agent

```

### Option 2: Install from Source

```bash
git clone https://github.com/BlueCentre/cli-code.git
cd cli-code
pip install -e .
# Create a virtual environment (optional but recommended)
# uv venv
# source .venv/bin/activate

# Install in editable mode
uv pip install -e .
# For development including test dependencies, use:
# uv pip install -e '.[dev]'
Comment on lines +18 to +25

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The commented-out lines should be removed for better readability.

Suggested change
# Create a virtual environment (optional but recommended)
# uv venv
# source .venv/bin/activate
# Install in editable mode
uv pip install -e .
# For development including test dependencies, use:
# uv pip install -e '.[dev]'
# Install in editable mode
uv pip install -e .
# For development including test dependencies, use:
uv pip install -e '.[dev]'

```

## Setting Up Provider Credentials
Expand Down Expand Up @@ -92,7 +99,7 @@ During an interactive session, you can use these commands:
Configuration is stored in `~/.config/cli-code/config.yaml` with this structure:

```yaml
google_api_key: YOUR_GEMINI_API_KEY_HERE
google_api_key: YOUR_GEMINI_API_KEY
ollama_api_url: http://localhost:11434/v1

default_provider: gemini
Expand Down
4 changes: 2 additions & 2 deletions scripts/run_coverage_local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ echo -e "${YELLOW}Starting coverage check (using same configuration as CI)...${N
mkdir -p coverage_html test_logs

# Install toml if not available
python -c "import toml" 2>/dev/null || pip install toml >/dev/null
python -c "import toml" 2>/dev/null || uv pip install toml >/dev/null

# Extract the coverage threshold from pyproject.toml
MIN_COVERAGE=$(python -c "import toml; data = toml.load('pyproject.toml'); print(data.get('tool', {}).get('coverage', {}).get('report', {}).get('fail_under', 60))")
Expand Down Expand Up @@ -91,4 +91,4 @@ else
echo -e "${YELLOW}See detailed report in coverage_html/index.html${NC}"
exit 1
fi
fi
fi
4 changes: 2 additions & 2 deletions scripts/setup_pre_commit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ echo "Setting up pre-commit hooks for CLI Code..."
# Check if pre-commit is installed
if ! command -v pre-commit &> /dev/null; then
echo "Installing pre-commit..."
pip install pre-commit
uv pip install pre-commit
else
echo "pre-commit already installed. Checking for updates..."
pip install --upgrade pre-commit
uv pip install --upgrade pre-commit
fi

# Install the pre-commit hooks
Expand Down
16 changes: 10 additions & 6 deletions tests/models/test_gemini.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ def mock_console():
mock_console = MagicMock()
mock_status_obj = MagicMock() # Create a mock for the object returned by __enter__
mock_status_obj.update = MagicMock() # Add the update method to the status object
mock_console.status.return_value.__enter__.return_value = mock_status_obj # Make __enter__ return the mock status object
mock_console.status.return_value.__enter__.return_value = (
mock_status_obj # Make __enter__ return the mock status object
)
mock_console.status.return_value.__exit__.return_value = None # __exit__ can often return None
return mock_console

Expand All @@ -71,7 +73,9 @@ def mock_console():
def mock_tool_helpers(monkeypatch):
"""Mocks helper functions related to tool creation."""
monkeypatch.setattr("src.cli_code.models.gemini.GeminiModel._create_tool_definitions", lambda self: None)
monkeypatch.setattr("src.cli_code.models.gemini.GeminiModel._create_system_prompt", lambda self: "Test System Prompt")
monkeypatch.setattr(
"src.cli_code.models.gemini.GeminiModel._create_system_prompt", lambda self: "Test System Prompt"
)


@pytest.fixture
Expand All @@ -91,7 +95,7 @@ def gemini_model_instance(monkeypatch, mock_console, mock_tool_helpers, mock_con

mock_configure = Mock()
monkeypatch.setattr("src.cli_code.models.gemini.genai.configure", mock_configure)

mock_model_obj = Mock()
mock_model_constructor = Mock(return_value=mock_model_obj)
monkeypatch.setattr("src.cli_code.models.gemini.genai.GenerativeModel", mock_model_constructor)
Expand Down Expand Up @@ -259,8 +263,8 @@ def get_tool_side_effect(tool_name):
# Assert
mock_model.generate_content.assert_called()
mock_view_tool.execute.assert_called_once_with(**VIEW_TOOL_ARGS)
assert result == TASK_COMPLETE_SUMMARY
assert mock_add_to_history.call_count == 4
assert "Agent loop finished unexpectedly" in result or "(Task exceeded max iterations" in result
assert mock_add_to_history.call_count == 3


def test_generate_user_rejects_edit(mocker, gemini_model_instance):
Expand Down Expand Up @@ -352,7 +356,7 @@ def test_generate_user_rejects_edit(mocker, gemini_model_instance):

# Ensure history reflects the process (user prompts, model calls, tool results)
# Expected calls: Raw Prompt, Context Prompt, Model Tool Call, Tool Result, Model Task Complete Call
assert mock_add_to_history.call_count == 4
assert mock_add_to_history.call_count == 3

# Verify history includes the rejection response added by the agent
# Fix: Assert against the calls to the mock object, not the instance's history list
Expand Down