Some checks failed
Build and Release / Lint and Test (push) Successful in 4m46s
Build and Release / Build Binaries (amd64, linux) (push) Failing after 42s
Build and Release / Build Binaries (amd64, darwin) (push) Has been cancelled
Build and Release / Build Binaries (amd64, windows) (push) Has been cancelled
Build and Release / Build Binaries (arm64, darwin) (push) Has been cancelled
Build and Release / Create Release (push) Has been cancelled
Build and Release / Build Binaries (arm64, linux) (push) Has been cancelled
Build and Release / Build Docker Image (push) Has been cancelled
Updated testing guide now covers: Phase 1: API Reliability - Request ID tracing - Rate limit headers - Chunk checksum verification - RFC 7807 error responses Phase 2: V2 API - V2 framework - Scalar docs - Batch operations - NDJSON streaming - AI context endpoints Phase 3: Reliability Patterns - Operation progress (SSE) - Idempotency middleware - Webhook retry - Circuit breaker Phase 4: SDK & CLI - gitea-cli tool - Go, Python, TypeScript, C#, Java SDKs Phase 5: New Features - Organization pinned repos - Public members - Gitea Pages (4 templates) - Wiki V2 API Also includes: - Complete smoke test script - Regression testing checklist - Rollback plan 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1010 lines
25 KiB
Markdown
1010 lines
25 KiB
Markdown
# Comprehensive Testing Guide for Gitea v1.26.0
|
|
|
|
## All Features to Test
|
|
|
|
| Phase | Feature | Risk | Priority |
|
|
|-------|---------|------|----------|
|
|
| **1** | Request ID Tracing | Low | Medium |
|
|
| **1** | Rate Limit Headers | Low | Medium |
|
|
| **1** | Chunk Checksum Verification | Medium | High |
|
|
| **1** | RFC 7807 Error Responses | Low | Medium |
|
|
| **2** | V2 API Framework | Medium | High |
|
|
| **2** | Structured Error Codes | Low | Medium |
|
|
| **2** | Scalar API Docs | Low | Low |
|
|
| **2** | Batch Operations | Medium | High |
|
|
| **2** | NDJSON Streaming | Medium | High |
|
|
| **2** | AI Context Endpoints | Low | Medium |
|
|
| **3** | Operation Progress (SSE) | Medium | High |
|
|
| **3** | Idempotency Middleware | High | Critical |
|
|
| **3** | Webhook Retry | Medium | High |
|
|
| **3** | Circuit Breaker | Medium | High |
|
|
| **4** | CLI Tool (gitea-cli) | Low | Medium |
|
|
| **4** | Go SDK | Low | Medium |
|
|
| **4** | Python SDK | Low | Medium |
|
|
| **4** | TypeScript SDK | Low | Medium |
|
|
| **4** | C# SDK | Low | Medium |
|
|
| **4** | Java SDK | Low | Medium |
|
|
| **5** | Organization Pinned Repos | Low | Medium |
|
|
| **5** | Organization Public Members | Low | Medium |
|
|
| **5** | Gitea Pages | Medium | High |
|
|
| **5** | Wiki V2 API | Medium | High |
|
|
|
|
---
|
|
|
|
## 1. Test Environment Setup
|
|
|
|
### Docker Test Instance
|
|
|
|
```bash
|
|
mkdir gitea-test && cd gitea-test
|
|
|
|
cat > docker-compose.yml << 'EOF'
|
|
version: "3"
|
|
services:
|
|
gitea:
|
|
image: gitea/gitea:1.26.0
|
|
container_name: gitea-test
|
|
environment:
|
|
- USER_UID=1000
|
|
- USER_GID=1000
|
|
- GITEA__database__DB_TYPE=sqlite3
|
|
- GITEA__server__ROOT_URL=http://localhost:3000/
|
|
volumes:
|
|
- ./gitea-data:/data
|
|
ports:
|
|
- "3000:3000"
|
|
- "2222:22"
|
|
EOF
|
|
|
|
docker-compose up -d
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Phase 1: API Reliability Enhancements
|
|
|
|
### 2.1 Request ID Tracing
|
|
|
|
```bash
|
|
# Test auto-generated request ID
|
|
curl -i http://localhost:3000/api/v1/version
|
|
# Should see: X-Request-ID: <short-uuid>
|
|
|
|
# Test custom request ID passed through
|
|
curl -i -H "X-Request-ID: my-custom-id-123" http://localhost:3000/api/v1/version
|
|
# Should see: X-Request-ID: my-custom-id-123
|
|
|
|
# Test request ID in error responses
|
|
curl -i http://localhost:3000/api/v1/repos/nonexistent/nonexistent
|
|
# Error JSON should contain request_id field
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] X-Request-ID header present in all responses
|
|
- [ ] Custom X-Request-ID passed through unchanged
|
|
- [ ] Request ID included in error response body
|
|
- [ ] Request ID appears in server logs
|
|
|
|
### 2.2 Rate Limit Headers
|
|
|
|
```bash
|
|
# Check rate limit headers
|
|
curl -i -H "Authorization: token $TOKEN" http://localhost:3000/api/v1/user
|
|
# Should see:
|
|
# X-RateLimit-Limit: <configured limit>
|
|
# X-RateLimit-Remaining: <remaining>
|
|
# X-RateLimit-Reset: <unix timestamp>
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Rate limit headers present on authenticated requests
|
|
- [ ] Remaining count decrements
|
|
- [ ] Reset timestamp is in the future
|
|
|
|
### 2.3 Chunk Checksum Verification
|
|
|
|
```bash
|
|
# Create a test file
|
|
echo "test content" > testfile.txt
|
|
CHECKSUM=$(sha256sum testfile.txt | cut -d' ' -f1)
|
|
|
|
# Upload with correct checksum (should succeed)
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "X-Chunk-Checksum: sha256=$CHECKSUM" \
|
|
-F "file=@testfile.txt" \
|
|
"http://localhost:3000/api/v1/repos/owner/repo/releases/1/assets"
|
|
|
|
# Upload with wrong checksum (should fail)
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "X-Chunk-Checksum: sha256=wrongchecksum123" \
|
|
-F "file=@testfile.txt" \
|
|
"http://localhost:3000/api/v1/repos/owner/repo/releases/1/assets"
|
|
# Should return 400 with checksum mismatch error
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Upload succeeds with correct checksum
|
|
- [ ] Upload fails with incorrect checksum
|
|
- [ ] Upload succeeds without checksum header (optional)
|
|
- [ ] Error message indicates checksum mismatch
|
|
|
|
### 2.4 RFC 7807 Error Responses
|
|
|
|
```bash
|
|
# Trigger a 404 error
|
|
curl -s http://localhost:3000/api/v1/repos/nonexistent/nonexistent | jq .
|
|
```
|
|
|
|
**Expected Response:**
|
|
```json
|
|
{
|
|
"type": "https://gitea.io/api/errors/not-found",
|
|
"title": "Not Found",
|
|
"status": 404,
|
|
"detail": "Repository not found",
|
|
"instance": "/api/v1/repos/nonexistent/nonexistent",
|
|
"request_id": "abc123",
|
|
"message": "Repository not found",
|
|
"url": "https://gitea.io/api/errors/not-found"
|
|
}
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Error responses include `type`, `title`, `status`, `detail`
|
|
- [ ] Legacy fields (`message`, `url`) still present for compatibility
|
|
- [ ] `request_id` included in errors
|
|
|
|
---
|
|
|
|
## 3. Phase 2: V2 API with AI Features
|
|
|
|
### 3.1 V2 API Framework
|
|
|
|
```bash
|
|
# Test v2 version endpoint
|
|
curl http://localhost:3000/api/v2/version
|
|
|
|
# Test v2 user endpoint (requires auth)
|
|
curl -H "Authorization: token $TOKEN" http://localhost:3000/api/v2/user
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] V2 endpoints respond at `/api/v2/`
|
|
- [ ] V1 endpoints still work at `/api/v1/`
|
|
- [ ] Authentication works on v2
|
|
|
|
### 3.2 Scalar API Documentation
|
|
|
|
```bash
|
|
# Open in browser
|
|
open http://localhost:3000/api/v2/docs
|
|
|
|
# Fetch OpenAPI spec
|
|
curl http://localhost:3000/api/v2/swagger.json
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Scalar docs page loads
|
|
- [ ] All v2 endpoints documented
|
|
- [ ] "Try it" functionality works
|
|
|
|
### 3.3 Batch Operations
|
|
|
|
```bash
|
|
# Batch get files
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"requests": [
|
|
{"owner": "org", "repo": "repo1", "path": "README.md", "ref": "main"},
|
|
{"owner": "org", "repo": "repo1", "path": "go.mod", "ref": "main"},
|
|
{"owner": "org", "repo": "repo2", "path": "package.json", "ref": "main"}
|
|
]
|
|
}' \
|
|
http://localhost:3000/api/v2/batch/files
|
|
|
|
# Batch get repos
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"repos": [
|
|
{"owner": "org", "repo": "repo1"},
|
|
{"owner": "org", "repo": "repo2"},
|
|
{"owner": "org", "repo": "repo3"}
|
|
]
|
|
}' \
|
|
http://localhost:3000/api/v2/batch/repos
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Batch files returns multiple file contents
|
|
- [ ] Batch repos returns multiple repo details
|
|
- [ ] Partial failures handled gracefully (some succeed, some fail)
|
|
- [ ] Performance better than individual requests
|
|
|
|
### 3.4 NDJSON Streaming
|
|
|
|
```bash
|
|
# Stream files
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-H "Accept: application/x-ndjson" \
|
|
-d '{"owner": "org", "repo": "repo", "paths": ["file1.go", "file2.go"]}' \
|
|
http://localhost:3000/api/v2/stream/files
|
|
|
|
# Stream commits
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-H "Accept: application/x-ndjson" \
|
|
-d '{"owner": "org", "repo": "repo", "ref": "main", "limit": 100}' \
|
|
http://localhost:3000/api/v2/stream/commits
|
|
|
|
# Stream issues
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-H "Accept: application/x-ndjson" \
|
|
-d '{"owner": "org", "repo": "repo", "state": "open"}' \
|
|
http://localhost:3000/api/v2/stream/issues
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Responses are newline-delimited JSON
|
|
- [ ] Each line is valid JSON
|
|
- [ ] Streaming starts before all data is ready
|
|
- [ ] Large datasets don't timeout
|
|
|
|
### 3.5 AI Context Endpoints
|
|
|
|
```bash
|
|
# Repository summary
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"owner": "org", "repo": "repo"}' \
|
|
http://localhost:3000/api/v2/ai/repo/summary
|
|
|
|
# Navigation hints
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"owner": "org", "repo": "repo"}' \
|
|
http://localhost:3000/api/v2/ai/repo/navigation
|
|
|
|
# Issue context
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"owner": "org", "repo": "repo", "issue_number": 1}' \
|
|
http://localhost:3000/api/v2/ai/issue/context
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Repo summary includes structure, languages, recent activity
|
|
- [ ] Navigation includes important paths, file types
|
|
- [ ] Issue context includes comments, labels, code references
|
|
- [ ] AI hints provided (project type, suggested files)
|
|
|
|
---
|
|
|
|
## 4. Phase 3: Reliability Patterns
|
|
|
|
### 4.1 Operation Progress (SSE)
|
|
|
|
```bash
|
|
# Start a long operation that returns operation ID
|
|
OPERATION_ID=$(curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
"http://localhost:3000/api/v1/repos/owner/repo/mirror-sync" | jq -r '.operation_id')
|
|
|
|
# Subscribe to progress updates (SSE)
|
|
curl -N -H "Accept: text/event-stream" \
|
|
"http://localhost:3000/api/v2/operations/$OPERATION_ID/progress"
|
|
|
|
# Check operation status
|
|
curl "http://localhost:3000/api/v2/operations/$OPERATION_ID"
|
|
|
|
# Cancel operation
|
|
curl -X DELETE "http://localhost:3000/api/v2/operations/$OPERATION_ID"
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Operation ID returned from long-running endpoints
|
|
- [ ] SSE stream provides real-time updates
|
|
- [ ] Progress includes phase, percentage, ETA
|
|
- [ ] Completed operations can be queried
|
|
- [ ] Operations can be cancelled
|
|
|
|
### 4.2 Idempotency Middleware
|
|
|
|
```bash
|
|
# First request - should execute
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Idempotency-Key: unique-key-123" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"title": "Test Issue", "body": "Test body"}' \
|
|
http://localhost:3000/api/v1/repos/owner/repo/issues
|
|
|
|
# Duplicate request - should return cached response
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Idempotency-Key: unique-key-123" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"title": "Test Issue", "body": "Test body"}' \
|
|
http://localhost:3000/api/v1/repos/owner/repo/issues
|
|
# Should see header: Idempotency-Replayed: true
|
|
# Should NOT create duplicate issue
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] First request executes normally
|
|
- [ ] Duplicate request returns cached response
|
|
- [ ] `Idempotency-Replayed: true` header on cached responses
|
|
- [ ] Different idempotency keys execute separately
|
|
- [ ] Keys expire after 24 hours
|
|
|
|
### 4.3 Webhook Retry
|
|
|
|
```bash
|
|
# Configure a webhook to a non-responsive endpoint
|
|
# Trigger an event (push, issue create, etc.)
|
|
# Check webhook delivery logs
|
|
|
|
curl -H "Authorization: token $TOKEN" \
|
|
"http://localhost:3000/api/v1/repos/owner/repo/hooks/1/deliveries"
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Failed deliveries are retried
|
|
- [ ] Exponential backoff between retries
|
|
- [ ] Max retries respected
|
|
- [ ] Delivery attempts logged
|
|
- [ ] Eventually marked as failed after max retries
|
|
|
|
### 4.4 Circuit Breaker
|
|
|
|
```bash
|
|
# This is internal - check via metrics or logs
|
|
# Simulate external service failure
|
|
# Verify circuit opens after threshold
|
|
# Verify circuit half-opens after timeout
|
|
# Verify circuit closes after success
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Circuit opens after consecutive failures
|
|
- [ ] Requests fail fast when circuit open
|
|
- [ ] Circuit transitions to half-open after timeout
|
|
- [ ] Successful request closes circuit
|
|
- [ ] Circuit state visible in health endpoint
|
|
|
|
---
|
|
|
|
## 5. Phase 4: SDK and CLI Tools
|
|
|
|
### 5.1 CLI Tool (gitea-cli)
|
|
|
|
```bash
|
|
# Build CLI
|
|
cd cmd/gitea-cli && go build -o gitea-cli .
|
|
|
|
# Login
|
|
./gitea-cli auth login --server http://localhost:3000 --token $TOKEN
|
|
|
|
# Check auth status
|
|
./gitea-cli auth status
|
|
|
|
# Upload release asset
|
|
./gitea-cli upload release-asset \
|
|
--owner myorg \
|
|
--repo myrepo \
|
|
--release-id 1 \
|
|
--file ./large-file.zip
|
|
|
|
# List pending uploads
|
|
./gitea-cli upload list
|
|
|
|
# Resume interrupted upload
|
|
./gitea-cli upload resume --session-id <session-id>
|
|
|
|
# Logout
|
|
./gitea-cli auth logout
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Login stores credentials securely
|
|
- [ ] Upload shows progress bar
|
|
- [ ] Chunked upload works for large files
|
|
- [ ] Resume works after interruption
|
|
- [ ] Checksum verification passes
|
|
|
|
### 5.2 Go SDK
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
gitea "code.gitea.io/gitea/sdk/go"
|
|
)
|
|
|
|
func main() {
|
|
client := gitea.NewClient("http://localhost:3000", "your-token")
|
|
|
|
// Get user
|
|
user, err := client.GetCurrentUser()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
fmt.Printf("Logged in as: %s\n", user.UserName)
|
|
|
|
// Upload file with progress
|
|
err = client.UploadReleaseAsset(
|
|
"owner", "repo", 1,
|
|
"./large-file.zip",
|
|
gitea.WithProgress(func(current, total int64) {
|
|
fmt.Printf("\rProgress: %d/%d", current, total)
|
|
}),
|
|
)
|
|
}
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Client initializes with token
|
|
- [ ] Basic API calls work
|
|
- [ ] Chunked upload works
|
|
- [ ] Progress callback fires
|
|
- [ ] Errors properly typed
|
|
|
|
### 5.3 Python SDK
|
|
|
|
```python
|
|
from gitea_sdk import GiteaClient
|
|
|
|
client = GiteaClient("http://localhost:3000", token="your-token")
|
|
|
|
# Get user
|
|
user = client.get_current_user()
|
|
print(f"Logged in as: {user.username}")
|
|
|
|
# Upload with progress
|
|
def on_progress(current, total):
|
|
print(f"\rProgress: {current}/{total}", end="")
|
|
|
|
client.upload_release_asset(
|
|
owner="myorg",
|
|
repo="myrepo",
|
|
release_id=1,
|
|
file_path="./large-file.zip",
|
|
on_progress=on_progress
|
|
)
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] pip install works
|
|
- [ ] Client connects with token
|
|
- [ ] Basic API calls work
|
|
- [ ] Type hints work in IDE
|
|
- [ ] Chunked upload works
|
|
|
|
### 5.4 TypeScript SDK
|
|
|
|
```typescript
|
|
import { GiteaClient } from '@gitea/sdk';
|
|
|
|
const client = new GiteaClient({
|
|
baseUrl: 'http://localhost:3000',
|
|
token: 'your-token'
|
|
});
|
|
|
|
// Get user
|
|
const user = await client.getCurrentUser();
|
|
console.log(`Logged in as: ${user.username}`);
|
|
|
|
// Upload with progress
|
|
await client.uploadReleaseAsset({
|
|
owner: 'myorg',
|
|
repo: 'myrepo',
|
|
releaseId: 1,
|
|
file: fs.createReadStream('./large-file.zip'),
|
|
onProgress: (current, total) => {
|
|
console.log(`Progress: ${current}/${total}`);
|
|
}
|
|
});
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] npm install works
|
|
- [ ] TypeScript types correct
|
|
- [ ] Works in Node.js
|
|
- [ ] Works in browser (where applicable)
|
|
- [ ] Async/await works properly
|
|
|
|
### 5.5 C# SDK
|
|
|
|
```csharp
|
|
using Gitea.SDK;
|
|
|
|
var client = new GiteaClient("http://localhost:3000", "your-token");
|
|
|
|
// Get user
|
|
var user = await client.GetCurrentUserAsync();
|
|
Console.WriteLine($"Logged in as: {user.UserName}");
|
|
|
|
// Upload with progress
|
|
await client.UploadReleaseAssetAsync(
|
|
owner: "myorg",
|
|
repo: "myrepo",
|
|
releaseId: 1,
|
|
filePath: "./large-file.zip",
|
|
onProgress: (current, total) => {
|
|
Console.WriteLine($"Progress: {current}/{total}");
|
|
}
|
|
);
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] NuGet package installs
|
|
- [ ] .NET 6+ compatible
|
|
- [ ] Async methods work
|
|
- [ ] Progress events fire
|
|
- [ ] Proper disposal (IDisposable)
|
|
|
|
### 5.6 Java SDK
|
|
|
|
```java
|
|
import io.gitea.sdk.GiteaClient;
|
|
|
|
GiteaClient client = new GiteaClient("http://localhost:3000", "your-token");
|
|
|
|
// Get user
|
|
User user = client.getCurrentUser();
|
|
System.out.println("Logged in as: " + user.getUserName());
|
|
|
|
// Upload with progress
|
|
client.uploadReleaseAsset(
|
|
"myorg", "myrepo", 1,
|
|
new File("./large-file.zip"),
|
|
(current, total) -> {
|
|
System.out.printf("Progress: %d/%d%n", current, total);
|
|
}
|
|
);
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Maven/Gradle dependency works
|
|
- [ ] Java 11+ compatible
|
|
- [ ] Fluent API works
|
|
- [ ] Progress callback fires
|
|
- [ ] Proper resource management
|
|
|
|
---
|
|
|
|
## 6. Phase 5: Organization Profiles
|
|
|
|
### 6.1 Pinned Repositories
|
|
|
|
```bash
|
|
# List pinned repos
|
|
curl -H "Authorization: token $TOKEN" \
|
|
"http://localhost:3000/api/v1/orgs/myorg/pinned"
|
|
|
|
# Pin a repository
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"repo_name": "my-repo"}' \
|
|
"http://localhost:3000/api/v1/orgs/myorg/pinned"
|
|
|
|
# Create a pinned group
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"name": "Core Projects"}' \
|
|
"http://localhost:3000/api/v1/orgs/myorg/pinned/groups"
|
|
|
|
# Add repo to group
|
|
curl -X PUT \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"group_id": 1}' \
|
|
"http://localhost:3000/api/v1/orgs/myorg/pinned/my-repo"
|
|
|
|
# Reorder pinned repos
|
|
curl -X PUT \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"order": ["repo1", "repo2", "repo3"]}' \
|
|
"http://localhost:3000/api/v1/orgs/myorg/pinned/reorder"
|
|
|
|
# Unpin repository
|
|
curl -X DELETE \
|
|
-H "Authorization: token $TOKEN" \
|
|
"http://localhost:3000/api/v1/orgs/myorg/pinned/my-repo"
|
|
```
|
|
|
|
**Web UI Checklist:**
|
|
- [ ] Pinned repos appear on org profile page
|
|
- [ ] Groups are collapsible
|
|
- [ ] Repo cards show stars, forks, language
|
|
- [ ] Reordering works via drag-and-drop (if implemented)
|
|
|
|
### 6.2 Public Members
|
|
|
|
```bash
|
|
# List public members with roles
|
|
curl "http://localhost:3000/api/v1/orgs/myorg/public_members/roles"
|
|
|
|
# Make yourself public
|
|
curl -X PUT \
|
|
-H "Authorization: token $TOKEN" \
|
|
"http://localhost:3000/api/v1/orgs/myorg/public_members/myusername"
|
|
|
|
# Remove public visibility
|
|
curl -X DELETE \
|
|
-H "Authorization: token $TOKEN" \
|
|
"http://localhost:3000/api/v1/orgs/myorg/public_members/myusername"
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Public members shown on org profile
|
|
- [ ] Roles displayed (Owner, Admin, Member)
|
|
- [ ] "and X more" overflow works
|
|
- [ ] Opt-in/opt-out works
|
|
|
|
---
|
|
|
|
## 7. Phase 5: Gitea Pages
|
|
|
|
### 7.1 Basic Pages Setup
|
|
|
|
```bash
|
|
# Create test repo with landing.yaml
|
|
mkdir test-pages && cd test-pages
|
|
git init
|
|
|
|
cat > .gitea/landing.yaml << 'EOF'
|
|
enabled: true
|
|
template: simple
|
|
|
|
branding:
|
|
primary_color: "#4a90d9"
|
|
|
|
hero:
|
|
title: "My Project"
|
|
tagline: "The best project ever"
|
|
EOF
|
|
|
|
cat > README.md << 'EOF'
|
|
# My Project
|
|
|
|
Welcome to my project!
|
|
|
|
## Features
|
|
- Feature 1
|
|
- Feature 2
|
|
EOF
|
|
|
|
git add -A && git commit -m "Initial commit"
|
|
git push origin main
|
|
```
|
|
|
|
### 7.2 Pages API
|
|
|
|
```bash
|
|
# Get pages config
|
|
curl -H "Authorization: token $TOKEN" \
|
|
"http://localhost:3000/api/v1/repos/owner/repo/pages"
|
|
|
|
# Enable pages
|
|
curl -X PUT \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"enabled": true, "template": "simple"}' \
|
|
"http://localhost:3000/api/v1/repos/owner/repo/pages"
|
|
|
|
# Add custom domain
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"domain": "myproject.example.com"}' \
|
|
"http://localhost:3000/api/v1/repos/owner/repo/pages/domains"
|
|
|
|
# Verify domain
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
"http://localhost:3000/api/v1/repos/owner/repo/pages/domains/myproject.example.com/verify"
|
|
|
|
# Disable pages
|
|
curl -X DELETE \
|
|
-H "Authorization: token $TOKEN" \
|
|
"http://localhost:3000/api/v1/repos/owner/repo/pages"
|
|
```
|
|
|
|
### 7.3 Template Testing
|
|
|
|
Test each template by visiting `http://localhost:3000/owner/repo/pages`:
|
|
|
|
**Simple Template:**
|
|
- [ ] Hero section displays
|
|
- [ ] README content renders
|
|
- [ ] Repo stats shown in footer
|
|
|
|
**Documentation Template:**
|
|
- [ ] Sidebar navigation works
|
|
- [ ] `/docs` folder content loads
|
|
- [ ] Search works (if enabled)
|
|
- [ ] "Edit this page" links work
|
|
|
|
**Product Template:**
|
|
- [ ] Hero with background
|
|
- [ ] Features grid displays
|
|
- [ ] Screenshot section works
|
|
- [ ] Releases section shows latest
|
|
|
|
**Portfolio Template:**
|
|
- [ ] Gallery grid displays
|
|
- [ ] Lightbox works on click
|
|
- [ ] Captions display
|
|
|
|
---
|
|
|
|
## 8. Phase 5: Wiki V2 API
|
|
|
|
### 8.1 CRUD Operations
|
|
|
|
```bash
|
|
BASE="http://localhost:3000/api/v2/repos/owner/repo/wiki"
|
|
|
|
# List pages
|
|
curl -H "Authorization: token $TOKEN" "$BASE/pages"
|
|
|
|
# Get single page
|
|
curl -H "Authorization: token $TOKEN" "$BASE/pages/Home"
|
|
|
|
# Create page
|
|
curl -X POST \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"name": "Test-Page", "content": "# Test\n\nContent here."}' \
|
|
"$BASE/pages"
|
|
|
|
# Update page
|
|
curl -X PUT \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"content": "# Updated\n\nNew content."}' \
|
|
"$BASE/pages/Test-Page"
|
|
|
|
# Rename page
|
|
curl -X PUT \
|
|
-H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"rename_to": "New-Page-Name"}' \
|
|
"$BASE/pages/Test-Page"
|
|
|
|
# Delete page
|
|
curl -X DELETE \
|
|
-H "Authorization: token $TOKEN" \
|
|
"$BASE/pages/New-Page-Name"
|
|
```
|
|
|
|
### 8.2 Search, Graph, Stats
|
|
|
|
```bash
|
|
# Search
|
|
curl -H "Authorization: token $TOKEN" "$BASE/search?q=installation"
|
|
|
|
# Link graph
|
|
curl -H "Authorization: token $TOKEN" "$BASE/graph"
|
|
|
|
# Statistics
|
|
curl -H "Authorization: token $TOKEN" "$BASE/stats"
|
|
|
|
# Page revisions
|
|
curl -H "Authorization: token $TOKEN" "$BASE/pages/Home/revisions"
|
|
```
|
|
|
|
### 8.3 Response Validation
|
|
|
|
**Page Response Should Include:**
|
|
- [ ] `content` - raw markdown
|
|
- [ ] `content_html` - rendered HTML
|
|
- [ ] `links_out` - outgoing wiki links
|
|
- [ ] `links_in` - incoming links
|
|
- [ ] `word_count` - accurate count
|
|
- [ ] `last_commit` - author, date, message
|
|
|
|
**Stats Response Should Include:**
|
|
- [ ] `total_pages`
|
|
- [ ] `total_words`
|
|
- [ ] `health.orphaned_pages`
|
|
- [ ] `health.dead_links`
|
|
- [ ] `health.outdated_pages`
|
|
- [ ] `health.short_pages`
|
|
- [ ] `top_linked`
|
|
|
|
---
|
|
|
|
## 9. Regression Testing
|
|
|
|
### Critical Existing Features
|
|
|
|
These MUST still work:
|
|
|
|
```bash
|
|
# Repository clone
|
|
git clone http://localhost:3000/owner/repo.git
|
|
|
|
# Push
|
|
git push origin main
|
|
|
|
# V1 API still works
|
|
curl http://localhost:3000/api/v1/version
|
|
curl -H "Authorization: token $TOKEN" http://localhost:3000/api/v1/user
|
|
curl http://localhost:3000/api/v1/repos/owner/repo
|
|
|
|
# Wiki V1 still works
|
|
curl http://localhost:3000/api/v1/repos/owner/repo/wiki/pages
|
|
curl http://localhost:3000/api/v1/repos/owner/repo/wiki/page/Home
|
|
|
|
# Issues
|
|
curl http://localhost:3000/api/v1/repos/owner/repo/issues
|
|
|
|
# Pull requests
|
|
curl http://localhost:3000/api/v1/repos/owner/repo/pulls
|
|
```
|
|
|
|
**Checklist:**
|
|
- [ ] Git clone (HTTP)
|
|
- [ ] Git clone (SSH)
|
|
- [ ] Git push
|
|
- [ ] Branch creation
|
|
- [ ] Tag creation
|
|
- [ ] Pull request creation
|
|
- [ ] Pull request merge
|
|
- [ ] Issue creation
|
|
- [ ] Wiki (web UI)
|
|
- [ ] Wiki (V1 API)
|
|
- [ ] User login
|
|
- [ ] Organization operations
|
|
|
|
---
|
|
|
|
## 10. Complete Smoke Test Script
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -e
|
|
|
|
BASE="${GITEA_URL:-http://localhost:3000}"
|
|
TOKEN="${GITEA_TOKEN:-your-token}"
|
|
OWNER="${TEST_OWNER:-testorg}"
|
|
REPO="${TEST_REPO:-testrepo}"
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
NC='\033[0m'
|
|
|
|
pass() { echo -e "${GREEN}✓${NC} $1"; }
|
|
fail() { echo -e "${RED}✗${NC} $1"; FAILED=1; }
|
|
|
|
test_endpoint() {
|
|
local name=$1
|
|
local method=${2:-GET}
|
|
local url=$3
|
|
local data=$4
|
|
|
|
if [ -n "$data" ]; then
|
|
response=$(curl -sf -X $method -H "Authorization: token $TOKEN" \
|
|
-H "Content-Type: application/json" -d "$data" "$url" 2>/dev/null) && pass "$name" || fail "$name"
|
|
else
|
|
response=$(curl -sf -X $method -H "Authorization: token $TOKEN" "$url" 2>/dev/null) && pass "$name" || fail "$name"
|
|
fi
|
|
}
|
|
|
|
echo "=== Gitea v1.26.0 Comprehensive Smoke Tests ==="
|
|
echo ""
|
|
|
|
echo "--- Phase 1: API Reliability ---"
|
|
test_endpoint "Version endpoint" GET "$BASE/api/v1/version"
|
|
test_endpoint "Request ID header" GET "$BASE/api/v1/version"
|
|
|
|
echo ""
|
|
echo "--- Phase 2: V2 API ---"
|
|
test_endpoint "V2 Version" GET "$BASE/api/v2/version"
|
|
test_endpoint "V2 User" GET "$BASE/api/v2/user"
|
|
test_endpoint "V2 Docs" GET "$BASE/api/v2/docs"
|
|
test_endpoint "V2 Batch Files" POST "$BASE/api/v2/batch/files" '{"requests":[]}'
|
|
test_endpoint "V2 AI Repo Summary" POST "$BASE/api/v2/ai/repo/summary" "{\"owner\":\"$OWNER\",\"repo\":\"$REPO\"}"
|
|
|
|
echo ""
|
|
echo "--- Phase 3: Reliability ---"
|
|
test_endpoint "Health Check" GET "$BASE/api/v2/health"
|
|
|
|
echo ""
|
|
echo "--- Phase 5: Org Profiles ---"
|
|
test_endpoint "Org Pinned Repos" GET "$BASE/api/v1/orgs/$OWNER/pinned"
|
|
test_endpoint "Org Public Members" GET "$BASE/api/v1/orgs/$OWNER/public_members/roles"
|
|
|
|
echo ""
|
|
echo "--- Phase 5: Pages ---"
|
|
test_endpoint "Pages Config" GET "$BASE/api/v1/repos/$OWNER/$REPO/pages"
|
|
|
|
echo ""
|
|
echo "--- Phase 5: Wiki V2 ---"
|
|
test_endpoint "Wiki List Pages" GET "$BASE/api/v2/repos/$OWNER/$REPO/wiki/pages"
|
|
test_endpoint "Wiki Search" GET "$BASE/api/v2/repos/$OWNER/$REPO/wiki/search?q=test"
|
|
test_endpoint "Wiki Graph" GET "$BASE/api/v2/repos/$OWNER/$REPO/wiki/graph"
|
|
test_endpoint "Wiki Stats" GET "$BASE/api/v2/repos/$OWNER/$REPO/wiki/stats"
|
|
|
|
echo ""
|
|
echo "--- Regression: V1 API ---"
|
|
test_endpoint "V1 User" GET "$BASE/api/v1/user"
|
|
test_endpoint "V1 Repos" GET "$BASE/api/v1/repos/$OWNER/$REPO"
|
|
test_endpoint "V1 Wiki Pages" GET "$BASE/api/v1/repos/$OWNER/$REPO/wiki/pages"
|
|
|
|
echo ""
|
|
if [ -z "$FAILED" ]; then
|
|
echo -e "${GREEN}All tests passed!${NC}"
|
|
exit 0
|
|
else
|
|
echo -e "${RED}Some tests failed!${NC}"
|
|
exit 1
|
|
fi
|
|
```
|
|
|
|
Save as `smoke-test.sh` and run:
|
|
```bash
|
|
chmod +x smoke-test.sh
|
|
GITEA_URL=http://localhost:3000 GITEA_TOKEN=your-token ./smoke-test.sh
|
|
```
|
|
|
|
---
|
|
|
|
## 11. Rollback Plan
|
|
|
|
If any issues are found:
|
|
|
|
```bash
|
|
# 1. Stop current version
|
|
docker-compose down
|
|
|
|
# 2. Restore previous version
|
|
docker pull gitea/gitea:1.25.3
|
|
|
|
# 3. Update docker-compose.yml to use 1.25.3
|
|
|
|
# 4. Start previous version
|
|
docker-compose up -d
|
|
```
|
|
|
|
**Safe to rollback because:**
|
|
- New tables (wiki_index, pages_*, org_pinned_*) are ignored by old version
|
|
- No existing tables were modified
|
|
- V1 API unchanged
|
|
- No data migration required
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
**Testing Priority:**
|
|
1. **Critical:** Idempotency, chunked uploads, V1 API regression
|
|
2. **High:** V2 batch/streaming, wiki V2 CRUD, pages rendering
|
|
3. **Medium:** SDKs, CLI, org profiles, operation progress
|
|
4. **Low:** Scalar docs, AI context endpoints
|
|
|
|
**Recommended Testing Time:**
|
|
- Automated tests: 30 minutes
|
|
- Manual testing: 2-4 hours
|
|
- Staging soak test: 24-48 hours
|
|
- Total: 2-3 days before production
|