Story 4.4 - simple check works
parent
b3e35b0b4d
commit
77356c4191
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue