Story 4.4 - simple check works

main
PeninsulaInd 2025-10-22 13:46:14 -05:00
parent b3e35b0b4d
commit 77356c4191
4 changed files with 246 additions and 2 deletions

View File

@ -0,0 +1,105 @@
# Story 4.4: Post-Deployment Verification - Implementation Summary
## Status: COMPLETE
Story points: 5
## Overview
Implemented a simple CLI command to verify deployed URLs return 200 OK status.
## Implementation
### New CLI Command
Added `verify-deployment` command to `src/cli/commands.py`:
```bash
uv run python main.py verify-deployment --batch-id <id> [--sample N] [--timeout 10]
```
**Options:**
- `--batch-id, -b`: Project/batch ID to verify (required)
- `--sample, -s`: Number of random URLs to check (optional, default: check all)
- `--timeout, -t`: Request timeout in seconds (default: 10)
### Core Functionality
1. Queries database for deployed articles in specified batch
2. Filters articles with `deployed_url` and status='deployed'
3. Makes HTTP GET requests to verify 200 OK status
4. Supports checking all URLs or random sample
5. Clear output showing success/failure for each URL
6. Summary report with total checked, successful, and failed counts
### Code Changes
- **Modified:** `src/cli/commands.py`
- Added imports: `requests`, `random`
- Added `verify_deployment()` command function
### Acceptance Criteria Verification
- ✅ CLI command available: `verify-deployment --batch_id <id>`
- ✅ Takes batch ID as input
- ✅ Retrieves URLs for all articles in batch from database
- ✅ Makes HTTP GET requests to sample or all URLs
- ✅ Reports which URLs return 200 OK and which do not
- ✅ Clear, easy-to-read output
- ✅ Can be run manually after deployment
## Usage Examples
### Verify all URLs in a batch:
```bash
uv run python main.py verify-deployment --batch-id 10
```
### Verify random sample of 5 URLs:
```bash
uv run python main.py verify-deployment --batch-id 10 --sample 5
```
### Custom timeout:
```bash
uv run python main.py verify-deployment --batch-id 10 --timeout 30
```
## Sample Output
```
Verifying deployment for batch: My Project (ID: 10)
Keyword: main keyword
Found 25 deployed articles
Checking all 25 URLs
✓ https://example.com/article-1.html
✓ https://example.com/article-2.html
✗ https://example.com/article-3.html (HTTP 404)
...
======================================================================
Verification Summary
======================================================================
Total checked: 25
Successful: 24
Failed: 1
Failed URLs:
https://example.com/article-3.html
Title: Article Three Title
Error: 404
======================================================================
```
## Dependencies
- `requests==2.32.5` (already in requirements.txt)
## Testing
- Command help output verified
- Follows existing CLI command patterns
- Simple, focused implementation per user requirements
## Notes
- No authentication required (read-only operation)
- Uses existing database repositories
- Minimal dependencies
- No freelance features added - strictly adheres to acceptance criteria
- Can be integrated into auto-deploy workflow in future if needed

View File

@ -0,0 +1,55 @@
# Story 4.4: Post-Deployment Verification - Quick Start
## Command Usage
Verify that deployed URLs are live and returning 200 OK status:
```bash
uv run python main.py verify-deployment --batch-id <id>
```
## Options
| Option | Short | Description | Default |
|--------|-------|-------------|---------|
| `--batch-id` | `-b` | Project/batch ID to verify | Required |
| `--sample` | `-s` | Number of random URLs to check | All |
| `--timeout` | `-t` | Request timeout in seconds | 10 |
## Examples
### Check all URLs in a batch
```bash
uv run python main.py verify-deployment --batch-id 10
```
### Check random sample of 5 URLs
```bash
uv run python main.py verify-deployment --batch-id 10 --sample 5
```
### Use custom timeout
```bash
uv run python main.py verify-deployment --batch-id 10 --timeout 30
```
## Output
The command will:
1. Show batch information
2. Display each URL check result with ✓ (success) or ✗ (failed)
3. Provide a summary of results
4. List failed URLs with error details
## Exit Codes
- `0`: All URLs returned 200 OK
- `1`: One or more URLs failed or error occurred
## Notes
- Only checks articles with `deployed_url` set and status='deployed'
- Follows redirects automatically
- No authentication required (read-only operation)
- Can be run multiple times safely

View File

@ -7,7 +7,7 @@ To deploy all finalized HTML content (articles and boilerplate pages) for a batc
- **Story 4.1**: ✅ COMPLETE (22 story points, real-world validated)
- **Story 4.2**: ✅ COMPLETE (implemented in Story 4.1)
- **Story 4.3**: ✅ COMPLETE (implemented in Story 4.1)
- **Story 4.4**: Not started
- **Story 4.4**: ✅ COMPLETE (5 story points)
- **Story 4.5**: Not started
## Stories
@ -64,7 +64,7 @@ To deploy all finalized HTML content (articles and boilerplate pages) for a batc
**Note:** The `last_deployed_at` timestamp for `site_deployments` could be added as enhancement if needed.
### Story 4.4: Post-Deployment Verification
**Status:** Not Started
**Status:** ✅ COMPLETE (5 story points)
**As a user**, I want a simple way to verify that a batch of articles has been deployed successfully, by checking a sample of URLs for a `200 OK` status, so I can have confidence the deployment worked.

View File

@ -24,6 +24,8 @@ from src.deployment.bunny_storage import BunnyStorageClient, BunnyStorageError
from src.deployment.deployment_service import DeploymentService
from src.deployment.url_logger import URLLogger
import os
import requests
import random
def authenticate_admin(username: str, password: str) -> Optional[User]:
@ -1098,5 +1100,87 @@ def deploy_batch(
raise click.Abort()
@app.command("verify-deployment")
@click.option('--batch-id', '-b', required=True, type=int, help='Project/batch ID to verify')
@click.option('--sample', '-s', type=int, help='Number of random URLs to check (default: check all)')
@click.option('--timeout', '-t', type=int, default=10, help='Request timeout in seconds (default: 10)')
def verify_deployment(batch_id: int, sample: Optional[int], timeout: int):
"""Verify deployed URLs return 200 OK status"""
try:
session = db_manager.get_session()
try:
content_repo = GeneratedContentRepository(session)
project_repo = ProjectRepository(session)
project = project_repo.get_by_id(batch_id)
if not project:
click.echo(f"Error: Project/batch {batch_id} not found", err=True)
raise click.Abort()
click.echo(f"Verifying deployment for batch: {project.name} (ID: {batch_id})")
click.echo(f"Keyword: {project.main_keyword}\n")
articles = content_repo.get_by_project_id(batch_id)
deployed_articles = [a for a in articles if a.deployed_url and a.status == 'deployed']
if not deployed_articles:
click.echo("No deployed articles found for this batch.")
return
click.echo(f"Found {len(deployed_articles)} deployed articles")
urls_to_check = deployed_articles
if sample and sample < len(deployed_articles):
urls_to_check = random.sample(deployed_articles, sample)
click.echo(f"Checking random sample of {sample} URLs\n")
else:
click.echo(f"Checking all {len(deployed_articles)} URLs\n")
successful = []
failed = []
for article in urls_to_check:
url = article.deployed_url
try:
response = requests.get(url, timeout=timeout, allow_redirects=True)
if response.status_code == 200:
successful.append((url, article.title))
click.echo(f"{url}")
else:
failed.append((url, article.title, response.status_code))
click.echo(f"{url} (HTTP {response.status_code})")
except requests.exceptions.RequestException as e:
failed.append((url, article.title, str(e)))
click.echo(f"{url} (Error: {type(e).__name__})")
click.echo("\n" + "=" * 70)
click.echo("Verification Summary")
click.echo("=" * 70)
click.echo(f"Total checked: {len(urls_to_check)}")
click.echo(f"Successful: {len(successful)}")
click.echo(f"Failed: {len(failed)}")
if failed:
click.echo("\nFailed URLs:")
for url, title, error in failed:
title_preview = title[:50] + "..." if len(title) > 50 else title
click.echo(f" {url}")
click.echo(f" Title: {title_preview}")
click.echo(f" Error: {error}")
click.echo("=" * 70)
if failed:
raise click.Abort()
finally:
session.close()
except Exception as e:
click.echo(f"Error verifying deployment: {e}", err=True)
raise click.Abort()
if __name__ == "__main__":
app()