diff --git a/.github/workflows/beta-release.yaml b/.github/workflows/beta-release.yaml deleted file mode 100644 index dab5001b5..000000000 --- a/.github/workflows/beta-release.yaml +++ /dev/null @@ -1,564 +0,0 @@ -name: Beta Release - -on: - push: - branches: - - beta - # - code-refactor/ObjectService - -jobs: - release-management: - runs-on: ubuntu-latest - steps: - - # Stap 1: Code ophalen - - name: Checkout Code - uses: actions/checkout@v3 - with: - fetch-depth: 0 - ssh-key: ${{ secrets.DEPLOY_KEY }} - - # Stap 2: Stel de appnaam in (gebruik de repo-naam) - - name: Set app env - run: | - echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV - - # Stap 3: Haal huidige versie uit info.xml, verhoog de patch en voeg beta-suffix toe - - name: Get current version and append beta suffix - id: increment_version - run: | - # Get version from main branch - git fetch origin main - main_version=$(git show origin/main:appinfo/info.xml | grep -oP '(?<=)[^<]+' || echo "") - - # Get current version from feature/php-linting branch - current_version=$(grep -oP '(?<=)[^<]+' appinfo/info.xml || echo "") - - # Split main version into parts - IFS='.' read -ra main_version_parts <<< "$main_version" - - # Increment patch version by 1 from main - next_patch=$((main_version_parts[2] + 1)) - - # Extract beta counter from current version if it exists - beta_counter=1 - if [[ $current_version =~ -beta\.([0-9]+)$ ]]; then - # If current patch version is still ahead of main, increment counter - current_patch=$(echo $current_version | grep -oP '^[0-9]+\.[0-9]+\.(\d+)' | cut -d. -f3) - if [ "$current_patch" -eq "$next_patch" ]; then - beta_counter=$((BASH_REMATCH[1] + 1)) - fi - fi - - beta_version="${main_version_parts[0]}.${main_version_parts[1]}.${next_patch}-beta.${beta_counter}" - - echo "NEW_VERSION=$beta_version" >> $GITHUB_ENV - echo "new_version=$beta_version" >> $GITHUB_OUTPUT - echo "Main version: $main_version" - echo "Current version: $current_version" - echo "Using beta version: $beta_version" - - # Stap 4: Genereer changelog entries vanaf laatste release met PR descriptions - # DISABLED: Taking too long (5+ minutes). Remove "if: false" to re-enable. - - name: Generate changelog entries from PRs - if: false - id: generate_changelog - run: | - # Get the date for the changelog entry - RELEASE_DATE=$(date +%Y-%m-%d) - - # Find the last release tag (beta or main) - LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") - - # Determine the base commit for finding PRs - if [ -z "$LAST_TAG" ]; then - # If no tag exists, use main branch as base - git fetch origin main - BASE_SHA=$(git rev-parse origin/main) - echo "No previous tag found, using main branch as base: $BASE_SHA" - else - # Use the tag as base - BASE_SHA=$(git rev-parse "$LAST_TAG") - echo "Found last tag: $LAST_TAG ($BASE_SHA)" - fi - - CURRENT_SHA=$(git rev-parse HEAD) - - # Create category files before processing - FEATURES_FILE=$(mktemp) - FIXES_FILE=$(mktemp) - DOCS_FILE=$(mktemp) - IMPROVEMENTS_FILE=$(mktemp) - OTHER_FILE=$(mktemp) - - # Track PRs we've already processed (by PR number) - PROCESSED_PRS=$(mktemp) - - # Fetch PRs that were merged into the beta branch - # We'll query PRs and check if their merge commit is in our range - echo "Fetching merged PRs from GitHub API..." - - # Get all commits in the range - COMMITS_IN_RANGE=$(git log --pretty=format:"%H" "$BASE_SHA..$CURRENT_SHA") - - # For each commit, check if it's a merge commit and find associated PR - for commit_sha in $COMMITS_IN_RANGE; do - # Skip if this commit is a version bump or skip-changelog - commit_msg=$(git log -1 --pretty=format:"%s" "$commit_sha") - if echo "$commit_msg" | grep -qiE "\[skip ci\]|Bump.*version|skip-changelog"; then - continue - fi - - # Try to find PR associated with this commit - # GitHub API: GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls - pr_data=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos/${{ github.repository }}/commits/$commit_sha/pulls" || echo "[]") - - # Parse PR numbers from response - pr_numbers=$(echo "$pr_data" | jq -r '.[].number' 2>/dev/null || echo "") - - if [ -n "$pr_numbers" ]; then - for pr_num in $pr_numbers; do - # Skip if we've already processed this PR - if grep -q "^$pr_num$" "$PROCESSED_PRS"; then - continue - fi - - # Mark as processed - echo "$pr_num" >> "$PROCESSED_PRS" - - # Fetch PR details - pr_info=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos/${{ github.repository }}/pulls/$pr_num" || echo "{}") - - # Check if PR is merged and not excluded - pr_state=$(echo "$pr_info" | jq -r '.state // "unknown"' 2>/dev/null) - pr_merged=$(echo "$pr_info" | jq -r '.merged // false' 2>/dev/null) - pr_labels=$(echo "$pr_info" | jq -r '[.labels[].name] | join(",")' 2>/dev/null || echo "") - - # Skip if PR is not merged or has skip-changelog label - if [ "$pr_state" != "closed" ] || [ "$pr_merged" != "true" ]; then - continue - fi - - if echo "$pr_labels" | grep -qi "skip-changelog"; then - echo "Skipping PR #$pr_num (has skip-changelog label)" - continue - fi - - # Extract PR information - pr_title=$(echo "$pr_info" | jq -r '.title // ""' 2>/dev/null) - pr_body=$(echo "$pr_info" | jq -r '.body // ""' 2>/dev/null) - pr_url=$(echo "$pr_info" | jq -r '.html_url // ""' 2>/dev/null) - - # Use PR description (body) if available, otherwise use title - if [ -n "$pr_body" ] && [ "$pr_body" != "null" ] && [ "$pr_body" != "" ]; then - # Clean up PR body - remove markdown code blocks, images, and formatting - # Extract first meaningful paragraph (skip empty lines and common prefixes) - pr_description=$(echo "$pr_body" | \ - sed -E 's/```[^`]*```//g' | \ - sed -E 's/!\[.*\]\(.*\)//g' | \ - sed -E 's/#+ //g' | \ - sed -E 's/^\*\*.*\*\*$//g' | \ - grep -v '^[[:space:]]*$' | \ - head -n 5 | \ - tr '\n' ' ' | \ - sed -E 's/^[[:space:]]+|[[:space:]]+$//g' | \ - sed -E 's/[[:space:]]+/ /g') - - # If description is too long, too short, or empty, use title - if [ ${#pr_description} -gt 250 ] || [ ${#pr_description} -lt 10 ] || [ -z "$pr_description" ]; then - pr_description="$pr_title" - fi - else - pr_description="$pr_title" - fi - - # Create entry with PR link - entry="- ${pr_description} ([#${pr_num}](${pr_url}))" - - # Categorize based on PR labels first (more accurate), then fall back to title/content - category="OTHER" - if echo "$pr_labels" | grep -qiE "(feature|feat|enhancement)"; then - category="FEATURES" - elif echo "$pr_labels" | grep -qiE "(bug|bugfix|fix|hotfix)"; then - category="FIXES" - elif echo "$pr_labels" | grep -qiE "(doc|docs|documentation)"; then - category="DOCS" - elif echo "$pr_labels" | grep -qiE "(refactor|perf|style|chore|improvements)"; then - category="IMPROVEMENTS" - elif echo "$pr_title" | grep -qiE "^(feat|feature|add|new):"; then - category="FEATURES" - elif echo "$pr_title" | grep -qiE "^(fix|bugfix|bug|hotfix):"; then - category="FIXES" - elif echo "$pr_title" | grep -qiE "^(doc|docs|documentation):"; then - category="DOCS" - elif echo "$pr_title" | grep -qiE "^(refactor|perf|style|chore|improve|improvement):"; then - category="IMPROVEMENTS" - fi - - # Write to appropriate category file - case "$category" in - FEATURES) - echo "$entry" >> "$FEATURES_FILE" - ;; - FIXES) - echo "$entry" >> "$FIXES_FILE" - ;; - DOCS) - echo "$entry" >> "$DOCS_FILE" - ;; - IMPROVEMENTS) - echo "$entry" >> "$IMPROVEMENTS_FILE" - ;; - *) - echo "$entry" >> "$OTHER_FILE" - ;; - esac - done - fi - done - - # Check if we found any PRs - total_entries=$(cat "$FEATURES_FILE" "$FIXES_FILE" "$DOCS_FILE" "$IMPROVEMENTS_FILE" "$OTHER_FILE" 2>/dev/null | wc -l) - - if [ "$total_entries" -eq 0 ]; then - echo "No merged PRs found for changelog" - echo "HAS_CHANGES=false" >> $GITHUB_OUTPUT - rm -f "$PROCESSED_PRS" "$FEATURES_FILE" "$FIXES_FILE" "$DOCS_FILE" "$IMPROVEMENTS_FILE" "$OTHER_FILE" - else - # Build changelog entry in a file - CHANGELOG_ENTRY_FILE=$(mktemp) - echo "## ${{ env.NEW_VERSION }} – ${RELEASE_DATE}" > "$CHANGELOG_ENTRY_FILE" - - if [ -s "$FEATURES_FILE" ]; then - echo "" >> "$CHANGELOG_ENTRY_FILE" - echo "### Added" >> "$CHANGELOG_ENTRY_FILE" - cat "$FEATURES_FILE" >> "$CHANGELOG_ENTRY_FILE" - fi - - if [ -s "$FIXES_FILE" ]; then - echo "" >> "$CHANGELOG_ENTRY_FILE" - echo "### Fixed" >> "$CHANGELOG_ENTRY_FILE" - cat "$FIXES_FILE" >> "$CHANGELOG_ENTRY_FILE" - fi - - if [ -s "$IMPROVEMENTS_FILE" ]; then - echo "" >> "$CHANGELOG_ENTRY_FILE" - echo "### Changed" >> "$CHANGELOG_ENTRY_FILE" - cat "$IMPROVEMENTS_FILE" >> "$CHANGELOG_ENTRY_FILE" - fi - - if [ -s "$DOCS_FILE" ]; then - echo "" >> "$CHANGELOG_ENTRY_FILE" - echo "### Documentation" >> "$CHANGELOG_ENTRY_FILE" - cat "$DOCS_FILE" >> "$CHANGELOG_ENTRY_FILE" - fi - - if [ -s "$OTHER_FILE" ]; then - echo "" >> "$CHANGELOG_ENTRY_FILE" - echo "### Other" >> "$CHANGELOG_ENTRY_FILE" - cat "$OTHER_FILE" >> "$CHANGELOG_ENTRY_FILE" - fi - - echo "" >> "$CHANGELOG_ENTRY_FILE" - - # Save changelog entry file path for next step - echo "$CHANGELOG_ENTRY_FILE" > changelog_entry_path.txt - - # Clean up temp files (except the entry file) - rm -f "$PRS_FILE" "$PROCESSED_PRS" "$FEATURES_FILE" "$FIXES_FILE" "$DOCS_FILE" "$IMPROVEMENTS_FILE" "$OTHER_FILE" - - echo "HAS_CHANGES=true" >> $GITHUB_OUTPUT - echo "✓ Generated changelog entry for ${{ env.NEW_VERSION }} with $total_entries PR entries" - fi - - echo "RELEASE_DATE=$RELEASE_DATE" >> $GITHUB_ENV - - # Stap 5: Update CHANGELOG.md met nieuwe entries - # DISABLED: Changelog generation is disabled. Remove "if: false" to re-enable. - - name: Update CHANGELOG.md - if: false - run: | - # Read changelog entry file path - if [ -f "changelog_entry_path.txt" ]; then - NEW_ENTRY_FILE=$(cat changelog_entry_path.txt) - - # Read current changelog and insert new entry - if [ -f "CHANGELOG.md" ]; then - # Insert new entry after "# Changelog" line and before first version entry - awk -v new_entry_file="$NEW_ENTRY_FILE" ' - /^# Changelog$/ { - print - getline - if (/^$/) print - # Read and print new entry - while ((getline line < new_entry_file) > 0) { - print line - } - close(new_entry_file) - # Print the line we read (empty line or first version) - if (!/^$/) print - next - } - { print } - ' CHANGELOG.md > CHANGELOG.md.tmp && mv CHANGELOG.md.tmp CHANGELOG.md - else - # Create new changelog file - echo "# Changelog" > CHANGELOG.md - echo "" >> CHANGELOG.md - cat "$NEW_ENTRY_FILE" >> CHANGELOG.md - fi - - # Clean up - rm -f "$NEW_ENTRY_FILE" changelog_entry_path.txt - echo "✓ CHANGELOG.md updated with version ${{ env.NEW_VERSION }}" - else - echo "Warning: changelog_entry_path.txt not found, skipping CHANGELOG.md update" - fi - - # Stap 6: Update de versie in info.xml - - name: Update version in info.xml - run: | - sed -i "s|.*|${{ env.NEW_VERSION }}|" appinfo/info.xml - - # Stap 7: Commit de nieuwe versie en changelog (indien er wijzigingen zijn) - - name: Commit version update and changelog - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - - # Check if there are changes to commit - if git diff --quiet && git diff --cached --quiet; then - echo "No changes to commit" - else - if [ "${{ steps.generate_changelog.outputs.HAS_CHANGES }}" == "true" ]; then - git add CHANGELOG.md appinfo/info.xml - git commit -m "Bump beta version to ${{ env.NEW_VERSION }} and update changelog [skip ci]" - else - git add appinfo/info.xml - git commit -m "Bump beta version to ${{ env.NEW_VERSION }} [skip ci]" - fi - git push - fi - - # Stap 6: Bereid de signing certificaten voor - - name: Prepare Signing Certificate and Key - run: | - echo "${{ secrets.NEXTCLOUD_SIGNING_CERT }}" > signing-cert.crt - echo "${{ secrets.NEXTCLOUD_SIGNING_KEY }}" > signing-key.key - - # Stap 7: Installeer npm dependencies - - name: Install npm dependencies - uses: actions/setup-node@v3 - with: - node-version: '18.x' - - # Stap 8: Stel PHP in en installeer benodigde extensies - - name: Set up PHP and install extensions - uses: shivammathur/setup-php@v2 - with: - php-version: '8.2' - extensions: zip, gd - - # Stap 9: Voer npm install, build en composer install uit - - run: npm ci - - run: npm run build - - run: composer install --no-dev --optimize-autoloader --classmap-authoritative - - # Stap 9a: Verify vendor dependencies are installed - - name: Verify vendor dependencies - run: | - echo "Checking critical dependencies..." - - # Check that vendor directory exists and has content - if [ ! -d "vendor" ] || [ -z "$(ls -A vendor 2>/dev/null)" ]; then - echo "ERROR: vendor directory is missing or empty" - exit 1 - fi - - # Check specific critical dependencies - missing_deps=0 - - if [ ! -d "vendor/openai-php/client/src" ]; then - echo "ERROR: openai-php/client source files not found" - missing_deps=1 - fi - - if [ ! -d "vendor/theodo-group/llphant/src" ]; then - echo "ERROR: theodo-group/llphant source files not found" - missing_deps=1 - fi - - if [ $missing_deps -eq 1 ]; then - echo "HINT: Check composer.json dependencies and composer install output" - exit 1 - fi - - echo "✓ All critical dependencies verified with source files" - - # Stap 10: Kopieer de bestanden naar de package directory - - name: Copy the package files into the package - run: | - mkdir -p package/${{ github.event.repository.name }} - rsync -av --progress \ - --exclude='/package' \ - --exclude='/.git' \ - --exclude='/.github' \ - --exclude='/.cursor' \ - --exclude='/.vscode' \ - --exclude='/.nextcloud' \ - --exclude='/docker' \ - --exclude='/docker-compose.yml' \ - --exclude='/docs' \ - --exclude='/website' \ - --exclude='/node_modules' \ - --exclude='/src' \ - --exclude='/phpcs-custom-sniffs' \ - --exclude='/resources' \ - --exclude='/tests' \ - --exclude='/path' \ - --exclude='/package.json' \ - --exclude='/package-lock.json' \ - --exclude='/composer.json' \ - --exclude='/composer.lock' \ - --exclude='/composer-setup.php' \ - --exclude='/phpcs.xml' \ - --exclude='/phpmd.xml' \ - --exclude='/psalm.xml' \ - --exclude='/phpunit.xml' \ - --exclude='/.phpunit.cache' \ - --exclude='.phpunit.result.cache' \ - --exclude='/jest.config.js' \ - --exclude='/webpack.config.js' \ - --exclude='/tsconfig.json' \ - --exclude='/.babelrc' \ - --exclude='/.eslintrc.js' \ - --exclude='/.prettierrc' \ - --exclude='/stylelint.config.js' \ - --exclude='/.spectral.yml' \ - --exclude='/.gitignore' \ - --exclude='/.gitattributes' \ - --exclude='/.php-cs-fixer.dist.php' \ - --exclude='/.nvmrc' \ - --exclude='/changelog-ci-config.json' \ - --exclude='/coverage.txt' \ - --exclude='/signing-key.key' \ - --exclude='/signing-cert.crt' \ - --exclude='/openapi.json' \ - --exclude='/*_ANALYSIS.md' \ - --exclude='/*_FIX.md' \ - --exclude='/*_SUMMARY.md' \ - --exclude='/*_GUIDE.md' \ - ./ package/${{ github.event.repository.name }}/ - - # Stap 11: Verify package contents before creating tarball - - name: Verify package vendor directory - run: | - echo "Verifying package contains complete vendor dependencies..." - - # Check vendor directory was copied - if [ ! -d "package/${{ github.event.repository.name }}/vendor" ]; then - echo "ERROR: vendor directory not found in package" - exit 1 - fi - - # Verify vendor packages have source files (not just LICENSE) - if [ ! -d "package/${{ github.event.repository.name }}/vendor/openai-php/client/src" ]; then - echo "ERROR: openai-php/client/src not found in package" - echo "HINT: Check rsync exclusion patterns - they may be too broad" - ls -la package/${{ github.event.repository.name }}/vendor/openai-php/client/ || true - exit 1 - fi - - # Quick sanity check: count vendor subdirectories - vendor_count=$(find package/${{ github.event.repository.name }}/vendor -maxdepth 1 -type d | wc -l) - if [ $vendor_count -lt 10 ]; then - echo "WARNING: Only $vendor_count vendor directories found (expected 20+)" - echo "Listing vendor contents:" - ls -la package/${{ github.event.repository.name }}/vendor/ - fi - - echo "✓ Package vendor directory verified with source files" - - # Stap 12: Maak het TAR.GZ archief - - name: Create Tarball - run: | - cd package && tar -czf ../nextcloud-release.tar.gz ${{ github.event.repository.name }} - - # Stap 13: Sign het TAR.GZ bestand met OpenSSL - - name: Sign the TAR.GZ file with OpenSSL - run: | - openssl dgst -sha512 -sign signing-key.key nextcloud-release.tar.gz | openssl base64 -out nextcloud-release.signature - - # Stap 13a: Upload tarball as workflow artifact for easy inspection - - name: Upload tarball as artifact - uses: actions/upload-artifact@v4 - with: - name: nextcloud-release-${{ env.NEW_VERSION }} - path: | - nextcloud-release.tar.gz - nextcloud-release.signature - retention-days: 30 - - # Stap 14: Genereer Git versie informatie (optioneel, voor logging) - - name: Git Version - id: version - uses: codacy/git-version@2.7.1 - with: - release-branch: beta - - # Stap 15: Extraheer repository description (optioneel) - - name: Extract repository description - id: repo-description - run: | - description=$(jq -r '.description' <(curl -s https://api.github.com/repos/${{ github.repository }})) - echo "REPO_DESCRIPTION=$description" >> $GITHUB_ENV - - # Stap 16: Output de versie (voor logging) - - name: Use the version - run: | - echo "Git Version info: ${{ steps.version.outputs.version }}" - - # Stap 17: Maak een nieuwe GitHub release (als prerelease) - - name: Upload Beta Release - uses: ncipollo/release-action@v1.12.0 - with: - tag: v${{ env.NEW_VERSION }} - name: Beta Release ${{ env.NEW_VERSION }} - draft: false - prerelease: true - skipIfReleaseExists: true - - # Stap 18: Voeg het tarball toe als asset aan de GitHub release - - name: Attach tarball to GitHub release - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: nextcloud-release.tar.gz - asset_name: ${{ env.APP_NAME }}-${{ env.NEW_VERSION }}.tar.gz - tag: v${{ env.NEW_VERSION }} - overwrite: true - - # Stap 19: Upload de app naar de Nextcloud App Store - - name: Upload app to Nextcloud appstore - uses: nextcloud-releases/nextcloud-appstore-push-action@a011fe619bcf6e77ddebc96f9908e1af4071b9c1 - with: - app_name: ${{ env.APP_NAME }} - appstore_token: ${{ secrets.NEXTCLOUD_APPSTORE_TOKEN }} - download_url: https://github.com/${{ github.repository }}/releases/download/v${{ env.NEW_VERSION }}/${{ env.APP_NAME }}-${{ env.NEW_VERSION }}.tar.gz - app_private_key: ${{ secrets.NEXTCLOUD_SIGNING_KEY }} - nightly: false - - # Stap 20: Verifieer de release - - name: Verify version and contents - run: | - echo "App version: ${{ env.NEW_VERSION }}" - echo "Tarball contents:" - tar -tvf nextcloud-release.tar.gz | head -100 - echo "Verify vendor directory in tarball:" - tar -tvf nextcloud-release.tar.gz | grep "vendor/openai-php/client" | head -5 || echo "WARNING: openai-php/client not found in tarball!" - echo "info.xml contents:" - tar -xOf nextcloud-release.tar.gz ${{ env.APP_NAME }}/appinfo/info.xml diff --git a/.github/workflows/branch-protection.yml b/.github/workflows/branch-protection.yml index 70bc56c0f..a6d20bbf7 100644 --- a/.github/workflows/branch-protection.yml +++ b/.github/workflows/branch-protection.yml @@ -1,247 +1,9 @@ -name: Branch Protection Check +name: Branch Protection on: pull_request: - branches: - - main - - master - - development - - dev + branches: [main, beta] jobs: - quality-gate: - name: Quality Gate Check - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '8.1' - extensions: mbstring, xml, ctype, iconv, intl, pdo, pdo_mysql, dom, filter, gd, json, posix, simplexml, xmlreader, xmlwriter, zip - coverage: xdebug - tools: composer:v2 - - - name: Install dependencies - run: composer install --prefer-dist --no-progress --no-interaction - - - name: Initialize Quality Gate Results - run: | - echo "QUALITY_GATE_PASSED=true" >> $GITHUB_ENV - echo "## 🚦 Quality Gate Status" >> $GITHUB_STEP_SUMMARY - - - name: Check 1 - PHP Syntax - id: syntax - run: | - echo "### ✅ Check 1: PHP Syntax" >> $GITHUB_STEP_SUMMARY - if composer lint; then - echo "✅ No syntax errors found" >> $GITHUB_STEP_SUMMARY - echo "status=pass" >> $GITHUB_OUTPUT - else - echo "❌ FAILED: Syntax errors detected" >> $GITHUB_STEP_SUMMARY - echo "status=fail" >> $GITHUB_OUTPUT - echo "QUALITY_GATE_PASSED=false" >> $GITHUB_ENV - fi - - - name: Check 2 - Coding Standards (PHPCS) - id: phpcs - run: | - echo "### Check 2: Coding Standards (PHPCS)" >> $GITHUB_STEP_SUMMARY - composer cs:check - composer phpcs:output - if [ -f phpcs-output.json ]; then - ERRORS=$(jq '.totals.errors' phpcs-output.json) - echo "errors=$ERRORS" >> $GITHUB_OUTPUT - if [ "$ERRORS" -eq "0" ]; then - echo "✅ PASSED: No PHPCS errors" >> $GITHUB_STEP_SUMMARY - echo "status=pass" >> $GITHUB_OUTPUT - else - echo "❌ FAILED: Found $ERRORS PHPCS errors (must be 0)" >> $GITHUB_STEP_SUMMARY - echo "status=fail" >> $GITHUB_OUTPUT - echo "QUALITY_GATE_PASSED=false" >> $GITHUB_ENV - fi - fi - continue-on-error: true - - - name: Check 3 - Code Quality (PHPMD) - id: phpmd - run: | - echo "### Check 3: Code Quality (PHPMD)" >> $GITHUB_STEP_SUMMARY - composer phpmd > phpmd-output.txt || true - VIOLATIONS=$(cat phpmd-output.txt | wc -l) - echo "violations=$VIOLATIONS" >> $GITHUB_OUTPUT - - # Allow up to 50 minor violations, fail if more - if [ "$VIOLATIONS" -le "50" ]; then - echo "✅ PASSED: $VIOLATIONS PHPMD violations (acceptable)" >> $GITHUB_STEP_SUMMARY - echo "status=pass" >> $GITHUB_OUTPUT - else - echo "❌ FAILED: $VIOLATIONS PHPMD violations (max 50)" >> $GITHUB_STEP_SUMMARY - echo "status=fail" >> $GITHUB_OUTPUT - echo "QUALITY_GATE_PASSED=false" >> $GITHUB_ENV - fi - continue-on-error: true - - - name: Check 4 - Overall Quality Score - id: quality - run: | - echo "### Check 4: Overall Quality Score" >> $GITHUB_STEP_SUMMARY - composer phpqa:ci || true - - if [ -f phpqa/phpqa.json ]; then - # Calculate composite quality score - PHPCS_ERRORS="${{ steps.phpcs.outputs.errors }}" - PHPMD_VIOLATIONS="${{ steps.phpmd.outputs.violations }}" - - # Score calculation: Start at 100, deduct points for issues - SCORE=$(echo "scale=2; 100 - ($PHPCS_ERRORS * 2) - ($PHPMD_VIOLATIONS * 0.1)" | bc) - - # Ensure score doesn't go negative - if (( $(echo "$SCORE < 0" | bc -l) )); then - SCORE=0 - fi - - echo "score=$SCORE" >> $GITHUB_OUTPUT - echo "Overall Quality Score: **$SCORE%**" >> $GITHUB_STEP_SUMMARY - - if (( $(echo "$SCORE >= 90" | bc -l) )); then - echo "✅ PASSED: Quality score meets 90% threshold" >> $GITHUB_STEP_SUMMARY - echo "status=pass" >> $GITHUB_OUTPUT - else - echo "❌ FAILED: Quality score ($SCORE%) below 90% threshold" >> $GITHUB_STEP_SUMMARY - echo "status=fail" >> $GITHUB_OUTPUT - echo "QUALITY_GATE_PASSED=false" >> $GITHUB_ENV - fi - else - echo "⚠️ WARNING: Could not calculate quality score" >> $GITHUB_STEP_SUMMARY - echo "status=unknown" >> $GITHUB_OUTPUT - fi - continue-on-error: true - - - name: Check 5 - Unit Tests - id: tests - run: | - echo "### Check 5: Unit Tests" >> $GITHUB_STEP_SUMMARY - if composer test:unit; then - echo "✅ PASSED: All unit tests pass" >> $GITHUB_STEP_SUMMARY - echo "status=pass" >> $GITHUB_OUTPUT - else - echo "⚠️ WARNING: Tests require Nextcloud environment" >> $GITHUB_STEP_SUMMARY - echo "status=skipped" >> $GITHUB_OUTPUT - fi - continue-on-error: true - - - name: Final Quality Gate Decision - run: | - echo "## 🏁 Final Result" >> $GITHUB_STEP_SUMMARY - - if [ "$QUALITY_GATE_PASSED" = "true" ]; then - echo "### ✅ QUALITY GATE PASSED" >> $GITHUB_STEP_SUMMARY - echo "This PR meets all quality requirements and can be merged." >> $GITHUB_STEP_SUMMARY - exit 0 - else - echo "### ❌ QUALITY GATE FAILED" >> $GITHUB_STEP_SUMMARY - echo "This PR does not meet quality requirements." >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Required actions:**" >> $GITHUB_STEP_SUMMARY - - if [ "${{ steps.syntax.outputs.status }}" = "fail" ]; then - echo "- Fix PHP syntax errors" >> $GITHUB_STEP_SUMMARY - fi - - if [ "${{ steps.phpcs.outputs.status }}" = "fail" ]; then - echo "- Fix PHPCS errors (run 'composer cs:fix')" >> $GITHUB_STEP_SUMMARY - fi - - if [ "${{ steps.phpmd.outputs.status }}" = "fail" ]; then - echo "- Refactor code to reduce PHPMD violations" >> $GITHUB_STEP_SUMMARY - fi - - if [ "${{ steps.quality.outputs.status }}" = "fail" ]; then - echo "- Improve overall code quality to reach 90% score" >> $GITHUB_STEP_SUMMARY - fi - - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Hint:** Run 'composer phpqa' locally to see detailed quality reports." >> $GITHUB_STEP_SUMMARY - exit 1 - fi - - - name: Upload Quality Reports - if: always() - uses: actions/upload-artifact@v3 - with: - name: quality-gate-reports - path: | - phpqa/ - phpcs-output.json - phpmd-output.txt - retention-days: 30 - - - name: Post Quality Gate Summary to PR - if: github.event_name == 'pull_request' - uses: actions/github-script@v7 - with: - script: | - const passed = '${{ env.QUALITY_GATE_PASSED }}' === 'true'; - const syntaxStatus = '${{ steps.syntax.outputs.status }}'; - const phpcsStatus = '${{ steps.phpcs.outputs.status }}'; - const phpmdStatus = '${{ steps.phpmd.outputs.status }}'; - const qualityStatus = '${{ steps.quality.outputs.status }}'; - const testsStatus = '${{ steps.tests.outputs.status }}'; - - const qualityScore = '${{ steps.quality.outputs.score }}'; - const phpcsErrors = '${{ steps.phpcs.outputs.errors }}'; - const phpmdViolations = '${{ steps.phpmd.outputs.violations }}'; - - const statusEmoji = (status) => { - if (status === 'pass') return '✅'; - if (status === 'fail') return '❌'; - if (status === 'skipped') return '⚠️'; - return '❓'; - }; - - const body = `## 🚦 Quality Gate Status: ${passed ? '✅ PASSED' : '❌ FAILED'} - - | Check | Status | Details | - |-------|--------|---------| - | PHP Syntax | ${statusEmoji(syntaxStatus)} ${syntaxStatus.toUpperCase()} | All PHP files must be valid | - | Coding Standards (PHPCS) | ${statusEmoji(phpcsStatus)} ${phpcsStatus.toUpperCase()} | Errors: ${phpcsErrors} (must be 0) | - | Code Quality (PHPMD) | ${statusEmoji(phpmdStatus)} ${phpmdStatus.toUpperCase()} | Violations: ${phpmdViolations} (max 50) | - | Overall Quality Score | ${statusEmoji(qualityStatus)} ${qualityStatus.toUpperCase()} | Score: ${qualityScore}% (min 90%) | - | Unit Tests | ${statusEmoji(testsStatus)} ${testsStatus.toUpperCase()} | Test suite status | - - ### Requirements for Merge - - ${passed ? - '✅ **All quality checks passed!** This PR meets the requirements for merging.' : - '❌ **Quality gate failed.** Please address the issues above before merging.'} - - ${!passed ? ` - ### How to Fix - - 1. Run \`composer cs:fix\` to auto-fix coding standards - 2. Run \`composer phpqa\` to see detailed quality reports - 3. Review the generated report at \`phpqa/phpqa-offline.html\` - 4. Fix any critical issues and re-push your changes - - 📚 See [Quality Assurance Documentation](../docs/quality-assurance.md) for more details. - ` : ''} - - 📊 Detailed reports are available in the workflow artifacts. - `; - - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: body - }); - continue-on-error: true - - - + check: + uses: ConductionNL/.github/.github/workflows/branch-protection.yml@main diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml new file mode 100644 index 000000000..781888bd8 --- /dev/null +++ b/.github/workflows/code-quality.yml @@ -0,0 +1,14 @@ +name: Code Quality + +on: + push: + branches: [main, development, feature/**, bugfix/**, hotfix/**] + pull_request: + branches: [main, beta, development] + +jobs: + quality: + uses: ConductionNL/.github/.github/workflows/quality.yml@main + with: + app-name: openregister + enable-phpunit: true diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index e538fe15e..774f76285 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -2,91 +2,12 @@ name: Documentation on: push: - branches: - - development + branches: [documentation] pull_request: - branches: - - development + branches: [documentation] jobs: deploy: - name: Deploy Documentation - runs-on: ubuntu-latest - # Only deploy on push, not on pull requests - if: github.event_name == 'push' - permissions: - contents: write - steps: - # https://github.com/marketplace/actions/checkout - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup Node.js 18 - uses: actions/setup-node@v3 - with: - node-version: '18' - - - name: Copy CONTRIBUTING.md to documentation - run: | - # Copy CONTRIBUTING.md to docs/development/ with Docusaurus frontmatter - { - echo "---" - echo "sidebar_position: 1" - echo "title: Contributing" - echo "description: Guidelines for contributing to OpenRegister, including PR descriptions and changelog formatting" - echo "---" - echo "" - cat CONTRIBUTING.md - } > docs/development/contributing.md - echo "✓ Copied CONTRIBUTING.md to docs/development/contributing.md" - - - name: Clear build cache and install dependencies - timeout-minutes: 3 - run: | - cd docusaurus - rm -rf node_modules/.cache - rm -rf .docusaurus - rm -rf build - npm run ci - - - name: Verify build output - run: | - cd docusaurus/build - if [ ! -f index.html ]; then - echo "ERROR: index.html not found in build directory!" - exit 1 - fi - - - name: Create .nojekyll and CNAME files - run: | - cd docusaurus/build - touch .nojekyll - echo "openregisters.app" > CNAME - - # Deploy to GitHub Pages - - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./docusaurus/build - publish_branch: gh-pages - user_name: 'github-actions[bot]' - user_email: 'github-actions[bot]@users.noreply.github.com' - force_orphan: false - allow_empty_commit: true - keep_files: false - - - name: Verify deployment - run: | - git fetch origin gh-pages - echo "✅ Deployment completed. Latest commit: $(git rev-parse origin/gh-pages)" - - # https://github.com/marketplace/actions/create-an-issue - - name: Create issue on failure - if: failure() - uses: JasonEtco/create-an-issue@v2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - filename: .github/DOCUMENTATION_ISSUE_TEMPLATE.md + uses: ConductionNL/.github/.github/workflows/documentation.yml@main + with: + cname: openregisters.app diff --git a/.github/workflows/issues-from-markdown.yml b/.github/workflows/issues-from-markdown.yml index a522f0061..9527bfb13 100644 --- a/.github/workflows/issues-from-markdown.yml +++ b/.github/workflows/issues-from-markdown.yml @@ -3,9 +3,10 @@ name: Create Issues from Markdown on: push: branches: - - main - - master - - development + # - main + # - master + # - development + - never paths: - 'issues/*.md' - '!issues/README.md' diff --git a/.github/workflows/pr-to-beta.yml b/.github/workflows/pr-to-beta.yml new file mode 100644 index 000000000..044b0da54 --- /dev/null +++ b/.github/workflows/pr-to-beta.yml @@ -0,0 +1,9 @@ +name: Create or update PR to beta + +on: + push: + branches: [development] + +jobs: + sync: + uses: ConductionNL/.github/.github/workflows/sync-to-beta.yml@main diff --git a/.github/workflows/pull-request-from-branch-check.yaml b/.github/workflows/pull-request-from-branch-check.yaml deleted file mode 100644 index 1c264ed99..000000000 --- a/.github/workflows/pull-request-from-branch-check.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: Branch Protection - -on: - pull_request: - branches: - - main - - beta - -jobs: - check-branch: - runs-on: ubuntu-latest - steps: - - name: Check branch - run: | - TARGET="${{ github.base_ref }}" - SOURCE="${{ github.head_ref }}" - - if [[ "$TARGET" == "main" ]]; then - if [[ "$SOURCE" != "beta" ]] && ! [[ "$SOURCE" =~ ^hotfix ]]; then - echo "Error: Pull requests to main must come from 'beta' or a branch starting with 'hotfix'" - echo "Source branch: $SOURCE" - exit 1 - fi - elif [[ "$TARGET" == "beta" ]]; then - if [[ "$SOURCE" != "development" ]] && ! [[ "$SOURCE" =~ ^hotfix ]]; then - echo "Error: Pull requests to beta must come from 'development' or a branch starting with 'hotfix'" - echo "Source branch: $SOURCE" - exit 1 - fi - fi - - echo "Branch check passed: $SOURCE -> $TARGET" diff --git a/.github/workflows/pull-request-lint-check.yaml b/.github/workflows/pull-request-lint-check.yaml deleted file mode 100644 index 4a8c874fe..000000000 --- a/.github/workflows/pull-request-lint-check.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: Lint Check - -on: - pull_request: - branches: - - development - - main - -jobs: - lint-check: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Install dependencies - run: npm i - - - name: Linting - run: npm run lint diff --git a/.github/workflows/push-development-to-beta.yaml b/.github/workflows/push-development-to-beta.yaml deleted file mode 100644 index a23f924ef..000000000 --- a/.github/workflows/push-development-to-beta.yaml +++ /dev/null @@ -1,44 +0,0 @@ -name: Create PR to Beta - -permissions: - contents: write - pull-requests: write - -on: - push: - branches: - - development - -jobs: - create-pr: - runs-on: ubuntu-latest - steps: - - name: Checkout Code - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Create or update PR to beta - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # Check if beta branch exists - if ! git ls-remote --heads origin beta | grep -q beta; then - echo "Beta branch does not exist yet. Creating from development..." - git push origin origin/development:refs/heads/beta - fi - - # Check if a PR already exists - EXISTING_PR=$(gh pr list --base beta --head development --state open --json number --jq '.[0].number' || echo "") - - if [ -n "$EXISTING_PR" ] && [ "$EXISTING_PR" != "null" ]; then - echo "PR #$EXISTING_PR already exists, it will auto-update with new commits" - else - gh pr create \ - --base beta \ - --head development \ - --title "Release: merge development into beta" \ - --body "Automated PR to sync development changes to beta for beta release. - - Merging this PR will trigger the beta release workflow." - fi diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml deleted file mode 100644 index 083fe4151..000000000 --- a/.github/workflows/quality.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Quality - -on: - push: - branches: [main, development, feature/**, bugfix/**, hotfix/**] - pull_request: - branches: [main, development] - -jobs: - quality: - uses: ConductionNL/.github/.github/workflows/quality.yml@feature/add-sbom-generation - with: - app-name: openregister - php-version: "8.3" - php-test-versions: '["8.3", "8.4"]' - nextcloud-test-refs: '["stable32"]' - enable-psalm: true - enable-phpstan: true - enable-phpmetrics: true - enable-frontend: true - enable-eslint: true - enable-phpunit: false # PHPUnit runs in database-tests.yml with PG + MariaDB matrix - enable-newman: false # Newman runs in database-tests.yml with PG + MariaDB matrix - enable-coverage-guard: true - enable-sbom: true diff --git a/.github/workflows/release-beta.yml b/.github/workflows/release-beta.yml new file mode 100644 index 000000000..d5aca1c75 --- /dev/null +++ b/.github/workflows/release-beta.yml @@ -0,0 +1,14 @@ +name: Beta Release + +on: + push: + branches: [beta] + +jobs: + release: + uses: ConductionNL/.github/.github/workflows/release-beta.yml@main + with: + app-name: openregister + verify-vendor-deps: true + vendor-check-paths: 'openai-php/client/src,theodo-group/llphant/src' + secrets: inherit diff --git a/.github/workflows/release-workflow.yaml b/.github/workflows/release-workflow.yaml deleted file mode 100644 index df91f49fc..000000000 --- a/.github/workflows/release-workflow.yaml +++ /dev/null @@ -1,303 +0,0 @@ -name: Release Workflow - -on: - push: - branches: - - main - - master - workflow_dispatch: - inputs: - version: - description: 'Version to release (leave empty to use info.xml version)' - required: false - default: '' - -jobs: - release-management: - runs-on: ubuntu-latest - steps: - - - name: Checkout Code - uses: actions/checkout@v3 - with: - fetch-depth: 0 - ssh-key: ${{ secrets.DEPLOY_KEY }} - - - name: Set app env - run: | - echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV - - - name: Get current version and increment - id: increment_version - run: | - current_version=$(grep -oP '(?<=)[^<]+' appinfo/info.xml) - IFS='.' read -ra version_parts <<< "$current_version" - ((version_parts[2]++)) - new_version="${version_parts[0]}.${version_parts[1]}.${version_parts[2]}" - echo "NEW_VERSION=$new_version" >> $GITHUB_ENV - echo "new_version=$new_version" >> $GITHUB_OUTPUT - - - name: Update version in info.xml - run: | - sed -i "s|.*|${{ env.NEW_VERSION }}|" appinfo/info.xml - - - name: Commit version update - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git commit -am "Bump version to ${{ env.NEW_VERSION }}" -m "[skip ci]" - git push - - # Step 1: Prepare the signing certificate and key - - name: Prepare Signing Certificate and Key - run: | - echo "${{ secrets.NEXTCLOUD_SIGNING_CERT }}" > signing-cert.crt - echo "${{ secrets.NEXTCLOUD_SIGNING_KEY }}" > signing-key.key - - # Step 3: Install Node.js dependencies using npm - - name: Install npm dependencies - uses: actions/setup-node@v3 - with: - node-version: '18.x' # Specify Node.js version - - # Step 4: Install PHP extensions - - name: Set up PHP and install extensions - uses: shivammathur/setup-php@v2 - with: - php-version: '8.2' - extensions: zip, gd - - # Step 5: Build the node dependencies - - run: npm ci - - # Step 6: Build the node dependencies - - run: npm run build - - # Step 7: Build composer dependencies - - run: composer install --no-dev --optimize-autoloader --classmap-authoritative - - # Step 7a: Verify vendor dependencies are installed - - name: Verify vendor dependencies - run: | - echo "Checking critical dependencies..." - - # Check that vendor directory exists and has content - if [ ! -d "vendor" ] || [ -z "$(ls -A vendor 2>/dev/null)" ]; then - echo "ERROR: vendor directory is missing or empty" - exit 1 - fi - - # Check specific critical dependencies - missing_deps=0 - - if [ ! -d "vendor/openai-php/client/src" ]; then - echo "ERROR: openai-php/client source files not found" - missing_deps=1 - fi - - if [ ! -d "vendor/theodo-group/llphant/src" ]; then - echo "ERROR: theodo-group/llphant source files not found" - missing_deps=1 - fi - - if [ $missing_deps -eq 1 ]; then - echo "HINT: Check composer.json dependencies and composer install output" - exit 1 - fi - - echo "✓ All critical dependencies verified with source files" - - # Step 8: Copy the files into the package directory - - name: Copy the package files into the package - run: | - mkdir -p package/${{ github.event.repository.name }} - rsync -av --progress \ - --exclude='/package' \ - --exclude='/.git' \ - --exclude='/.github' \ - --exclude='/.cursor' \ - --exclude='/.vscode' \ - --exclude='/.nextcloud' \ - --exclude='/docker' \ - --exclude='/docker-compose.yml' \ - --exclude='/docs' \ - --exclude='/website' \ - --exclude='/node_modules' \ - --exclude='/src' \ - --exclude='/phpcs-custom-sniffs' \ - --exclude='/resources' \ - --exclude='/tests' \ - --exclude='/path' \ - --exclude='/package.json' \ - --exclude='/package-lock.json' \ - --exclude='/composer.json' \ - --exclude='/composer.lock' \ - --exclude='/composer-setup.php' \ - --exclude='/phpcs.xml' \ - --exclude='/phpmd.xml' \ - --exclude='/psalm.xml' \ - --exclude='/phpunit.xml' \ - --exclude='/.phpunit.cache' \ - --exclude='.phpunit.result.cache' \ - --exclude='/jest.config.js' \ - --exclude='/webpack.config.js' \ - --exclude='/tsconfig.json' \ - --exclude='/.babelrc' \ - --exclude='/.eslintrc.js' \ - --exclude='/.prettierrc' \ - --exclude='/stylelint.config.js' \ - --exclude='/.spectral.yml' \ - --exclude='/.gitignore' \ - --exclude='/.gitattributes' \ - --exclude='/.php-cs-fixer.dist.php' \ - --exclude='/.nvmrc' \ - --exclude='/changelog-ci-config.json' \ - --exclude='/coverage.txt' \ - --exclude='/signing-key.key' \ - --exclude='/signing-cert.crt' \ - --exclude='/openapi.json' \ - --exclude='/*_ANALYSIS.md' \ - --exclude='/*_FIX.md' \ - --exclude='/*_SUMMARY.md' \ - --exclude='/*_GUIDE.md' \ - ./ package/${{ github.event.repository.name }}/ - - # Step 8a: Verify package contents before creating tarball - - name: Verify package vendor directory - run: | - echo "Verifying package contains complete vendor dependencies..." - - # Check vendor directory was copied - if [ ! -d "package/${{ github.event.repository.name }}/vendor" ]; then - echo "ERROR: vendor directory not found in package" - exit 1 - fi - - # Verify vendor packages have source files (not just LICENSE) - if [ ! -d "package/${{ github.event.repository.name }}/vendor/openai-php/client/src" ]; then - echo "ERROR: openai-php/client/src not found in package" - echo "HINT: Check rsync exclusion patterns - they may be too broad" - ls -la package/${{ github.event.repository.name }}/vendor/openai-php/client/ || true - exit 1 - fi - - # Quick sanity check: count vendor subdirectories - vendor_count=$(find package/${{ github.event.repository.name }}/vendor -maxdepth 1 -type d | wc -l) - if [ $vendor_count -lt 10 ]; then - echo "WARNING: Only $vendor_count vendor directories found (expected 20+)" - echo "Listing vendor contents:" - ls -la package/${{ github.event.repository.name }}/vendor/ - fi - - echo "✓ Package vendor directory verified with source files" - - # Step 9: Create the TAR.GZ archive - - name: Create Tarball - run: | - cd package && tar -czf ../nextcloud-release.tar.gz ${{ github.event.repository.name }} - - # Step 10: Sign the TAR.GZ file with OpenSSL - - name: Sign the TAR.GZ file with OpenSSL - run: | - openssl dgst -sha512 -sign signing-key.key nextcloud-release.tar.gz | openssl base64 -out nextcloud-release.signature - - # Step 10a: Upload tarball as workflow artifact for easy inspection - - name: Upload tarball as artifact - uses: actions/upload-artifact@v4 - with: - name: nextcloud-release-${{ env.NEW_VERSION }} - path: | - nextcloud-release.tar.gz - nextcloud-release.signature - retention-days: 30 - - # Step 11: Generate Git version information - - name: Git Version - id: version - uses: codacy/git-version@2.7.1 - with: - release-branch: main - - # Step 12: Extract repository description - - name: Extract repository description - id: repo-description - run: | - description=$(jq -r '.description' <(curl -s https://api.github.com/repos/${{ github.repository }})) - echo "REPO_DESCRIPTION=$description" >> $GITHUB_ENV - - # Step 14: Output the version - - name: Use the version - run: | - echo ${{ steps.version.outputs.version }} - - # Step 18: Create a new release on GitHub - - name: Upload Release - uses: ncipollo/release-action@v1.12.0 - with: - tag: v${{ env.NEW_VERSION }} - name: Release ${{ env.NEW_VERSION }} - draft: false - prerelease: false - - - name: Attach tarball to github release - uses: svenstaro/upload-release-action@04733e069f2d7f7f0b4aebc4fbdbce8613b03ccd # v2 - id: attach_to_release - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: nextcloud-release.tar.gz # Corrected spelling - asset_name: ${{ env.APP_NAME }}-${{ env.NEW_VERSION }}.tar.gz - tag: v${{ env.NEW_VERSION }} - overwrite: true - - - name: Upload app to Nextcloud appstore - uses: nextcloud-releases/nextcloud-appstore-push-action@a011fe619bcf6e77ddebc96f9908e1af4071b9c1 # v1 - with: - app_name: ${{ env.APP_NAME }} - appstore_token: ${{ secrets.NEXTCLOUD_APPSTORE_TOKEN }} - download_url: https://github.com/${{ github.repository }}/releases/download/v${{ env.NEW_VERSION }}/${{ env.APP_NAME }}-${{ env.NEW_VERSION }}.tar.gz - app_private_key: ${{ secrets.NEXTCLOUD_SIGNING_KEY }} - nightly: false - - - name: Verify version and contents - run: | - echo "App version: ${{ env.NEW_VERSION }}" - echo "Tarball contents:" - tar -tvf nextcloud-release.tar.gz | head -100 - echo "Verify vendor directory in tarball:" - tar -tvf nextcloud-release.tar.gz | grep "vendor/openai-php/client" | head -5 || echo "WARNING: openai-php/client not found in tarball!" - echo "info.xml contents:" - tar -xOf nextcloud-release.tar.gz ${{ env.APP_NAME }}/appinfo/info.xml - - # DISABLED: Changelog generation was taking too long (5+ minutes). - # To re-enable, uncomment this job. - # update-changelog: - # runs-on: ubuntu-latest - # steps: - # - # - name: Checkout Code - # uses: actions/checkout@v3 - # with: - # fetch-depth: 0 - # - # - name: Set app env - # run: | - # echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV - # - # - name: Get current version and increment - # id: increment_version - # run: | - # current_version=$(grep -oP '(?<=)[^<]+' appinfo/info.xml) - # IFS='.' read -ra version_parts <<< "$current_version" - # ((version_parts[2]++)) - # new_version="${version_parts[0]}.${version_parts[1]}.${version_parts[2]}" - # echo "NEW_VERSION=$new_version" >> $GITHUB_ENV - # echo "new_version=$new_version" >> $GITHUB_OUTPUT - # - # # Step 13: Run Changelog CI - # - name: Run Changelog CI - # if: github.ref == 'refs/heads/main' - # uses: saadmk11/changelog-ci@v1.1.2 - # with: - # persist-credentials: true - # release_version: ${{ env.NEW_VERSION }} - # config_file: changelog-ci-config.json diff --git a/.github/workflows/unstable-release.yaml b/.github/workflows/unstable-release.yaml deleted file mode 100644 index eddda8193..000000000 --- a/.github/workflows/unstable-release.yaml +++ /dev/null @@ -1,310 +0,0 @@ -name: Unstable Release - -on: - push: - branches: - - development - - feature/php-linting - -jobs: - release-management: - runs-on: ubuntu-latest - steps: - - # Step 1: Checkout Code - - name: Checkout Code - uses: actions/checkout@v3 - with: - fetch-depth: 0 - ssh-key: ${{ secrets.DEPLOY_KEY }} - - # Step 2: Set the app name (use the repo name) - - name: Set app env - run: | - echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV - - # Step 3: Get current version from info.xml, increment patch and add unstable suffix - - name: Get current version and append unstable suffix - id: increment_version - run: | - # Get current version from the branch - current_version=$(grep -oP '(?<=)[^<]+' appinfo/info.xml || echo "") - - # Strip any existing suffix (-unstable.X, -beta.X) to get base version - base_version=$(echo "$current_version" | grep -oP '^[0-9]+\.[0-9]+\.[0-9]+') - - # Split base version into parts - IFS='.' read -ra version_parts <<< "$base_version" - - # Extract unstable counter from current version if it exists - unstable_counter=1 - if [[ $current_version =~ -unstable\.([0-9]+)$ ]]; then - unstable_counter=$((BASH_REMATCH[1] + 1)) - fi - - unstable_version="${version_parts[0]}.${version_parts[1]}.${version_parts[2]}-unstable.${unstable_counter}" - - echo "NEW_VERSION=$unstable_version" >> $GITHUB_ENV - echo "new_version=$unstable_version" >> $GITHUB_OUTPUT - echo "Current version: $current_version" - echo "Base version: $base_version" - echo "Using unstable version: $unstable_version" - - # Step 4: Update the version in info.xml - - name: Update version in info.xml - run: | - sed -i "s|.*|${{ env.NEW_VERSION }}|" appinfo/info.xml - - # Step 5: Commit the new version - - name: Commit version update - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - - # Check if there are changes to commit - if git diff --quiet && git diff --cached --quiet; then - echo "No changes to commit" - else - git add appinfo/info.xml - git commit -m "Bump unstable version to ${{ env.NEW_VERSION }} [skip ci]" - git push - fi - - # Step 6: Prepare the signing certificates - - name: Prepare Signing Certificate and Key - run: | - echo "${{ secrets.NEXTCLOUD_SIGNING_CERT }}" > signing-cert.crt - echo "${{ secrets.NEXTCLOUD_SIGNING_KEY }}" > signing-key.key - - # Step 7: Install npm dependencies - - name: Install npm dependencies - uses: actions/setup-node@v3 - with: - node-version: '18.x' - - # Step 8: Set up PHP and install required extensions - - name: Set up PHP and install extensions - uses: shivammathur/setup-php@v2 - with: - php-version: '8.2' - extensions: zip, gd - - # Step 9: Run npm install, build and composer install - - run: npm ci - - run: npm run build - - run: composer install --no-dev --optimize-autoloader --classmap-authoritative - - # Step 9a: Verify vendor dependencies are installed - - name: Verify vendor dependencies - run: | - echo "Checking critical dependencies..." - - # Check that vendor directory exists and has content - if [ ! -d "vendor" ] || [ -z "$(ls -A vendor 2>/dev/null)" ]; then - echo "ERROR: vendor directory is missing or empty" - exit 1 - fi - - # Check specific critical dependencies - missing_deps=0 - - if [ ! -d "vendor/openai-php/client/src" ]; then - echo "ERROR: openai-php/client source files not found" - missing_deps=1 - fi - - if [ ! -d "vendor/theodo-group/llphant/src" ]; then - echo "ERROR: theodo-group/llphant source files not found" - missing_deps=1 - fi - - if [ $missing_deps -eq 1 ]; then - echo "HINT: Check composer.json dependencies and composer install output" - exit 1 - fi - - echo "✓ All critical dependencies verified with source files" - - # Step 10: Copy the files into the package directory - - name: Copy the package files into the package - run: | - mkdir -p package/${{ github.event.repository.name }} - rsync -av --progress \ - --exclude='/package' \ - --exclude='/.git' \ - --exclude='/.github' \ - --exclude='/.cursor' \ - --exclude='/.vscode' \ - --exclude='/.nextcloud' \ - --exclude='/docker' \ - --exclude='/docker-compose.yml' \ - --exclude='/docs' \ - --exclude='/website' \ - --exclude='/node_modules' \ - --exclude='/src' \ - --exclude='/phpcs-custom-sniffs' \ - --exclude='/resources' \ - --exclude='/tests' \ - --exclude='/path' \ - --exclude='/package.json' \ - --exclude='/package-lock.json' \ - --exclude='/composer.json' \ - --exclude='/composer.lock' \ - --exclude='/composer-setup.php' \ - --exclude='/phpcs.xml' \ - --exclude='/phpmd.xml' \ - --exclude='/psalm.xml' \ - --exclude='/phpunit.xml' \ - --exclude='/.phpunit.cache' \ - --exclude='.phpunit.result.cache' \ - --exclude='/jest.config.js' \ - --exclude='/webpack.config.js' \ - --exclude='/tsconfig.json' \ - --exclude='/.babelrc' \ - --exclude='/.eslintrc.js' \ - --exclude='/.prettierrc' \ - --exclude='/stylelint.config.js' \ - --exclude='/.spectral.yml' \ - --exclude='/.gitignore' \ - --exclude='/.gitattributes' \ - --exclude='/.php-cs-fixer.dist.php' \ - --exclude='/.nvmrc' \ - --exclude='/changelog-ci-config.json' \ - --exclude='/coverage.txt' \ - --exclude='/signing-key.key' \ - --exclude='/signing-cert.crt' \ - --exclude='/openapi.json' \ - --exclude='/*_ANALYSIS.md' \ - --exclude='/*_FIX.md' \ - --exclude='/*_SUMMARY.md' \ - --exclude='/*_GUIDE.md' \ - ./ package/${{ github.event.repository.name }}/ - - # Step 11: Verify package contents before creating tarball - - name: Verify package vendor directory - run: | - echo "Verifying package contains complete vendor dependencies..." - - # Check vendor directory was copied - if [ ! -d "package/${{ github.event.repository.name }}/vendor" ]; then - echo "ERROR: vendor directory not found in package" - exit 1 - fi - - # Verify vendor packages have source files (not just LICENSE) - if [ ! -d "package/${{ github.event.repository.name }}/vendor/openai-php/client/src" ]; then - echo "ERROR: openai-php/client/src not found in package" - echo "HINT: Check rsync exclusion patterns - they may be too broad" - ls -la package/${{ github.event.repository.name }}/vendor/openai-php/client/ || true - exit 1 - fi - - # Quick sanity check: count vendor subdirectories - vendor_count=$(find package/${{ github.event.repository.name }}/vendor -maxdepth 1 -type d | wc -l) - if [ $vendor_count -lt 10 ]; then - echo "WARNING: Only $vendor_count vendor directories found (expected 20+)" - echo "Listing vendor contents:" - ls -la package/${{ github.event.repository.name }}/vendor/ - fi - - echo "✓ Package vendor directory verified with source files" - - # Step 12: Create the TAR.GZ archive - - name: Create Tarball - run: | - cd package && tar -czf ../nextcloud-release.tar.gz ${{ github.event.repository.name }} - - # Step 13: Sign the TAR.GZ file with OpenSSL - - name: Sign the TAR.GZ file with OpenSSL - run: | - openssl dgst -sha512 -sign signing-key.key nextcloud-release.tar.gz | openssl base64 -out nextcloud-release.signature - - # Step 13a: Upload tarball as workflow artifact for easy inspection - - name: Upload tarball as artifact - uses: actions/upload-artifact@v4 - with: - name: nextcloud-release-${{ env.NEW_VERSION }} - path: | - nextcloud-release.tar.gz - nextcloud-release.signature - retention-days: 30 - - # Step 14: Generate Git version information (optional, for logging) - - name: Git Version - id: version - uses: codacy/git-version@2.7.1 - with: - release-branch: development - - # Step 15: Extract repository description (optional) - - name: Extract repository description - id: repo-description - run: | - description=$(jq -r '.description' <(curl -s https://api.github.com/repos/${{ github.repository }})) - echo "REPO_DESCRIPTION=$description" >> $GITHUB_ENV - - # Step 16: Output the version (for logging) - - name: Use the version - run: | - echo "Git Version info: ${{ steps.version.outputs.version }}" - - # Step 17: Create a new GitHub release (as prerelease) - - name: Upload Unstable Release - uses: ncipollo/release-action@v1.12.0 - with: - tag: v${{ env.NEW_VERSION }} - name: Unstable Release ${{ env.NEW_VERSION }} - draft: false - prerelease: true - - # Step 18: Attach the tarball as asset to the GitHub release - - name: Attach tarball to GitHub release - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: nextcloud-release.tar.gz - asset_name: ${{ env.APP_NAME }}-${{ env.NEW_VERSION }}.tar.gz - tag: v${{ env.NEW_VERSION }} - overwrite: true - - # Step 19: Upload the app to the Nextcloud App Store as unstable/nightly - - name: Upload app to Nextcloud appstore - run: | - DOWNLOAD_URL="https://github.com/${{ github.repository }}/releases/download/v${{ env.NEW_VERSION }}/${{ env.APP_NAME }}-${{ env.NEW_VERSION }}.tar.gz" - echo "${{ secrets.NEXTCLOUD_SIGNING_KEY }}" > /tmp/app.key - SIGNATURE=$(openssl dgst -sha512 -sign /tmp/app.key nextcloud-release.tar.gz | openssl base64 | tr -d '\n') - rm /tmp/app.key - - echo "Uploading to Nextcloud App Store (nightly)..." - echo "Version: ${{ env.NEW_VERSION }}" - echo "Download URL: ${DOWNLOAD_URL}" - - RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \ - "https://apps.nextcloud.com/api/v1/apps/releases" \ - -H "Authorization: Token ${{ secrets.NEXTCLOUD_APPSTORE_TOKEN }}" \ - -H "Content-Type: application/json" \ - -d "{\"download\": \"${DOWNLOAD_URL}\", \"signature\": \"${SIGNATURE}\", \"nightly\": true}") - - HTTP_CODE=$(echo "$RESPONSE" | tail -1) - BODY=$(echo "$RESPONSE" | sed '$d') - - echo "HTTP Status: ${HTTP_CODE}" - echo "Response body: ${BODY}" - - if [ "$HTTP_CODE" -ge 400 ]; then - echo "::error::App store upload failed with HTTP ${HTTP_CODE}: ${BODY}" - exit 1 - fi - - echo "Successfully uploaded to Nextcloud App Store" - - # Step 20: Verify the release - - name: Verify version and contents - run: | - echo "App version: ${{ env.NEW_VERSION }}" - echo "Tarball contents:" - tar -tvf nextcloud-release.tar.gz | head -100 - echo "Verify vendor directory in tarball:" - tar -tvf nextcloud-release.tar.gz | grep "vendor/openai-php/client" | head -5 || echo "WARNING: openai-php/client not found in tarball!" - echo "info.xml contents:" - tar -xOf nextcloud-release.tar.gz ${{ env.APP_NAME }}/appinfo/info.xml