Merge pull request #77 from dawnsystem/claude/fix-github-tests-019ptUhQs4TYnT2CyQNLV6bF

Claude/fix GitHub tests 019pt uh qs4 t yn t2 cy qnlv6b f
This commit is contained in:
dawnsystem 2025-11-18 00:15:20 +01:00 committed by GitHub
commit d1dcb7c678
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 188 additions and 45 deletions

View file

@ -74,6 +74,100 @@ jobs:
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
- name: Check files
uses: pre-commit/action@v3.0.1
verify-environment:
name: "Verify Environment & Services"
runs-on: ubuntu-24.04
needs:
- pre-commit
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Verify Docker installation
run: |
if ! command -v docker &> /dev/null; then
echo "✗ Docker is not installed"
exit 1
fi
echo "✓ Docker is installed: $(docker --version)"
- name: Verify docker-compose installation
run: |
if ! command -v docker &> /dev/null || ! docker compose version &> /dev/null; then
echo "✗ docker-compose is not installed"
exit 1
fi
echo "✓ docker compose is installed: $(docker compose version)"
- name: Verify compose file exists
env:
COMPOSE_FILE: docker/compose/docker-compose.intellidocs.yml
run: |
if [ ! -f "$COMPOSE_FILE" ]; then
echo "✗ Compose file not found: $COMPOSE_FILE"
exit 1
fi
echo "✓ Compose file found: $COMPOSE_FILE"
- name: Set up Python
id: setup-python
uses: actions/setup-python@v6
with:
python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
version: ${{ env.DEFAULT_UV_VERSION }}
enable-cache: true
python-version: ${{ steps.setup-python.outputs.python-version }}
- name: Generate and verify requirements.txt
run: |
uv export --quiet --no-dev --all-extras --format requirements-txt --output-file requirements.txt
if [ ! -f "requirements.txt" ]; then
echo "✗ requirements.txt was not generated"
exit 1
fi
echo "✓ requirements.txt generated successfully"
- name: Verify Python dependencies installation
run: |
# Verify that requirements.txt can be parsed
if ! python -c "
import sys
try:
with open('requirements.txt', 'r') as f:
lines = f.readlines()
print(f'✓ requirements.txt has {len(lines)} entries')
sys.exit(0)
except Exception as e:
print(f'✗ Error reading requirements.txt: {e}')
sys.exit(1)
"; then
exit 1
fi
- name: Start Redis service
run: |
docker compose --file docker/compose/docker-compose.intellidocs.yml up -d broker
echo "Waiting for Redis to be ready..."
sleep 10
- name: Verify Redis is responding
run: |
MAX_RETRIES=30
RETRY_COUNT=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
if docker compose --file docker/compose/docker-compose.intellidocs.yml exec -T broker redis-cli ping &> /dev/null; then
echo "✓ Redis is responding"
exit 0
fi
RETRY_COUNT=$((RETRY_COUNT + 1))
echo "Waiting for Redis... (attempt $RETRY_COUNT/$MAX_RETRIES)"
sleep 2
done
echo "✗ Redis is not responding after $MAX_RETRIES attempts"
docker compose --file docker/compose/docker-compose.intellidocs.yml logs broker
exit 1
- name: Stop services
if: always()
run: |
docker compose --file docker/compose/docker-compose.intellidocs.yml down -v
documentation:
name: "Build & Deploy Documentation"
runs-on: ubuntu-24.04

View file

@ -25,10 +25,10 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: '3.12'
@ -104,7 +104,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
@ -242,7 +242,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Create Release
uses: softprops/action-gh-release@v2

View file

@ -83,11 +83,18 @@ jobs:
const pr = context.payload.pull_request;
const user = pr.user.login;
const { data: members } = await github.rest.orgs.listMembers({
org: 'paperless-ngx',
});
// Try to get org members, but handle if this is not an org
let memberLogins = [];
try {
const { data: members } = await github.rest.orgs.listMembers({
org: context.repo.owner,
});
memberLogins = members.map(m => m.login.toLowerCase());
} catch (error) {
// If not an organization, only skip for repo collaborators
core.info('Not an organization or unable to fetch members');
}
const memberLogins = members.map(m => m.login.toLowerCase());
if (memberLogins.includes(user.toLowerCase())) {
core.info('Skipping comment: user is org member');
return;
@ -98,7 +105,7 @@ jobs:
"Thank you very much for submitting this PR to us!\n\n" +
"This is what will happen next:\n\n" +
"1. CI tests will run against your PR to ensure quality and consistency.\n" +
"2. Next, human contributors from paperless-ngx review your changes.\n" +
"2. Next, human contributors will review your changes.\n" +
"3. Please address any issues that come up during the review as soon as you are able to.\n" +
"4. If accepted, your pull request will be merged into the `dev` branch and changes there will be tested further.\n" +
"5. Eventually, changes from you and other contributors will be merged into `main` and a new release will be made.\n\n" +

View file

@ -63,6 +63,7 @@ jobs:
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
file_pattern: 'src-ui/messages.xlf src/locale/en_US/LC_MESSAGES/django.po'
commit_message: "Auto translate strings"
commit_user_name: "GitHub Actions"

View file

@ -18,8 +18,8 @@ import {
} from '@angular/core'
import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { Subject } from 'rxjs'
import { takeUntil } from 'rxjs/operators'
import { Subject, of } from 'rxjs'
import { takeUntil, catchError } from 'rxjs/operators'
import {
AISuggestion,
AISuggestionStatus,
@ -134,10 +134,19 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
(s) => s.type === AISuggestionType.Tag
)
if (tagSuggestions.length > 0) {
this.tagService.listAll().pipe(takeUntil(this.destroy$)).subscribe((tags) => {
this.tags = tags.results
this.updateSuggestionLabels()
})
this.tagService
.listAll()
.pipe(
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load tags:', error)
return of({ results: [] })
})
)
.subscribe((tags) => {
this.tags = tags.results
this.updateSuggestionLabels()
})
}
// Load correspondents if needed
@ -145,10 +154,19 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
(s) => s.type === AISuggestionType.Correspondent
)
if (correspondentSuggestions.length > 0) {
this.correspondentService.listAll().pipe(takeUntil(this.destroy$)).subscribe((correspondents) => {
this.correspondents = correspondents.results
this.updateSuggestionLabels()
})
this.correspondentService
.listAll()
.pipe(
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load correspondents:', error)
return of({ results: [] })
})
)
.subscribe((correspondents) => {
this.correspondents = correspondents.results
this.updateSuggestionLabels()
})
}
// Load document types if needed
@ -156,10 +174,19 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
(s) => s.type === AISuggestionType.DocumentType
)
if (documentTypeSuggestions.length > 0) {
this.documentTypeService.listAll().pipe(takeUntil(this.destroy$)).subscribe((documentTypes) => {
this.documentTypes = documentTypes.results
this.updateSuggestionLabels()
})
this.documentTypeService
.listAll()
.pipe(
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load document types:', error)
return of({ results: [] })
})
)
.subscribe((documentTypes) => {
this.documentTypes = documentTypes.results
this.updateSuggestionLabels()
})
}
// Load storage paths if needed
@ -167,10 +194,19 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
(s) => s.type === AISuggestionType.StoragePath
)
if (storagePathSuggestions.length > 0) {
this.storagePathService.listAll().pipe(takeUntil(this.destroy$)).subscribe((storagePaths) => {
this.storagePaths = storagePaths.results
this.updateSuggestionLabels()
})
this.storagePathService
.listAll()
.pipe(
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load storage paths:', error)
return of({ results: [] })
})
)
.subscribe((storagePaths) => {
this.storagePaths = storagePaths.results
this.updateSuggestionLabels()
})
}
// Load custom fields if needed
@ -178,10 +214,19 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
(s) => s.type === AISuggestionType.CustomField
)
if (customFieldSuggestions.length > 0) {
this.customFieldsService.listAll().pipe(takeUntil(this.destroy$)).subscribe((customFields) => {
this.customFields = customFields.results
this.updateSuggestionLabels()
})
this.customFieldsService
.listAll()
.pipe(
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load custom fields:', error)
return of({ results: [] })
})
)
.subscribe((customFields) => {
this.customFields = customFields.results
this.updateSuggestionLabels()
})
}
}

View file

@ -1,6 +1,6 @@
import { HttpClient } from '@angular/common/http'
import { Injectable, inject } from '@angular/core'
import { BehaviorSubject, Observable, interval, Subscription } from 'rxjs'
import { BehaviorSubject, Observable, interval, Subscription, of } from 'rxjs'
import { catchError, map, startWith, switchMap } from 'rxjs/operators'
import { AIStatus } from 'src/app/data/ai-status'
import { environment } from 'src/environments/environment'
@ -86,19 +86,15 @@ export class AIStatusService {
}),
catchError((error) => {
this.loading = false
console.warn('Failed to fetch AI status, using mock data:', error)
// Return mock data if endpoint doesn't exist yet
return [
{
active: true,
processing: false,
documents_scanned_today: 42,
suggestions_applied: 15,
pending_deletion_requests: 2,
last_scan: new Date().toISOString(),
version: '1.0.0',
},
]
console.warn('Failed to fetch AI status:', error)
// Return default status if endpoint fails
return of({
active: false,
processing: false,
documents_scanned_today: 0,
suggestions_applied: 0,
pending_deletion_requests: 0,
})
})
)
}