name: Update Plugins JSON on: schedule: # Run weekly on Mondays at 00:00 UTC - cron: '0 0 * * 1' # Allow manual triggering workflow_dispatch: permissions: contents: write jobs: update-plugins: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up PHP uses: shivammathur/setup-php@v2 with: php-version: '8.4' tools: none - name: Fetch and process plugin repositories env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | #!/bin/bash set -e cat > /tmp/parse_plugin.php << 'PHPEOF' 0) { if ($token === '[') { $array_depth++; } elseif ($token === ']' || $token === ')') { $array_depth--; if ($array_depth === 0) { // End of return array - save any pending element if ($current_element !== '') { $array_elements[] = $current_element; } break; } } elseif ($token === ',') { // Comma separates array elements $array_elements[] = $current_element; $current_element = ''; } } continue; } // Look for 'function about' if ($token[0] === T_FUNCTION) { // Check if next non-whitespace token is 'about' $j = $i + 1; while ($j < count($tokens) && is_array($tokens[$j]) && $tokens[$j][0] === T_WHITESPACE) { $j++; } if ($j < count($tokens) && is_array($tokens[$j]) && $tokens[$j][0] === T_STRING && $tokens[$j][1] === 'about') { $in_about = true; $i = $j; continue; } } if ($in_about && $token[0] === T_RETURN) { $in_return = true; continue; } if ($in_return) { // Track array() syntax if ($token[0] === T_ARRAY) { // Look ahead for opening parenthesis (skip whitespace) $k = $i + 1; while ($k < count($tokens) && is_array($tokens[$k]) && $tokens[$k][0] === T_WHITESPACE) { $k++; } if ($k < count($tokens) && $tokens[$k] === '(') { $array_depth++; } } elseif ($array_depth > 0) { // We're inside the array, collect element values if ($token[0] === T_CONSTANT_ENCAPSED_STRING) { // String literal $str = $token[1]; $str = substr($str, 1, -1); $str = stripcslashes($str); $current_element = $str; } elseif ($token[0] === T_STRING && in_array(strtolower($token[1]), ['null', 'true', 'false'])) { // null, true, false keywords $current_element = $token[1]; } } } // Handle [ syntax for arrays if ($in_return && !is_array($token) && $token === '[') { $array_depth = 1; } } // Description is at index 1 if (isset($array_elements[1])) { $description = $array_elements[1]; } echo json_encode(['class_name' => $class_name, 'description' => $description], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); PHPEOF # Get all repositories from tt-rss organization that start with tt-rss-plugin- echo "Fetching repositories from tt-rss organization..." plugins_json="[]" page=1 while true; do response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ -H "Accept: application/vnd.github.v3+json" \ "https://api.github.com/orgs/tt-rss/repos?type=public&per_page=100&page=$page") # Check for API errors if echo "$response" | jq -e '.message' >/dev/null 2>&1; then echo "API Error: $(echo "$response" | jq -r '.message')" exit 1 fi # Check if we got an empty array (no more pages) if [ "$(echo "$response" | jq '. | length')" -eq 0 ]; then break fi # Filter repositories that start with tt-rss-plugin- and are not archived filtered=$(echo "$response" | jq '[.[] | select(.name | startswith("tt-rss-plugin-")) | select(.archived == false)]') # Process each repository for repo in $(echo "$filtered" | jq -r '.[] | @base64'); do _jq() { echo "$repo" | base64 --decode | jq -r "$1" } repo_name=$(_jq '.name') full_name=$(_jq '.full_name') html_url=$(_jq '.html_url') clone_url=$(_jq '.clone_url') repo_description=$(_jq '.description // ""') echo "Processing repository: $repo_name" # Get the latest commit timestamp commits_response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ -H "Accept: application/vnd.github.v3+json" \ "https://api.github.com/repos/$full_name/commits?per_page=1") # Check if commits response is valid if echo "$commits_response" | jq -e '.[0]' >/dev/null 2>&1; then last_update=$(echo "$commits_response" | jq -r '.[0].commit.committer.date') else echo " Warning: Could not fetch commit info for $repo_name" last_update="" fi # Skip if no last_update (indicates repository might be empty or inaccessible) if [ -z "$last_update" ]; then echo " Skipping $repo_name: no commit history found" continue fi # Try to fetch init.php init_php=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ -H "Accept: application/vnd.github.v3.raw" \ "https://api.github.com/repos/$full_name/contents/init.php" 2>/dev/null || echo "") # Try to extract the class name and plugin description from init.php class_name="" description="" if [ -n "$init_php" ]; then # Save init.php to temporary file for PHP processing temp_file=$(mktemp) echo "$init_php" > "$temp_file" php_output=$(php /tmp/parse_plugin.php "$temp_file" 2>/dev/null || echo '{"class_name":"","description":""}') class_name=$(echo "$php_output" | jq -r '.class_name // ""') description=$(echo "$php_output" | jq -r '.description // ""') rm -f "$temp_file" fi # Skip if no class name was found if [ -z "$class_name" ]; then echo " Skipping $repo_name: no class name found in init.php" continue fi # Fallback to repository description if no description was found if [ -z "$description" ]; then description="$repo_description" fi # Placeholder description if still empty if [ -z "$description" ]; then description="" fi # Create topics array topics=$(echo "$class_name" | tr '[:upper:]' '[:lower:]') topics_json="[\"$topics\"]" # Build plugin JSON object plugin_json=$(jq -n \ --arg name "$class_name" \ --arg description "$description" \ --argjson topics "$topics_json" \ --arg html_url "$html_url" \ --arg clone_url "$clone_url" \ --arg last_update "$last_update" \ '{ name: $name, description: $description, topics: $topics, html_url: $html_url, clone_url: $clone_url, last_update: $last_update }') # Append to plugins array plugins_json=$(echo "$plugins_json" | jq --argjson plugin "$plugin_json" '. += [$plugin]') done page=$((page + 1)) done # Sort by name and save echo "$plugins_json" | jq 'sort_by(.name)' > plugins.json echo "Plugin list updated successfully!" cat plugins.json - name: Deploy to gh-pages branch run: | # Save plugins.json to a safe location outside the repo cp plugins.json /tmp/plugins.json git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" # Fetch gh-pages branch git fetch origin gh-pages 2>/dev/null || true if git rev-parse --verify origin/gh-pages >/dev/null 2>&1; then # gh-pages exists # Remove the local plugins.json first to avoid conflicts rm -f plugins.json git checkout gh-pages else # Create new orphan gh-pages branch git checkout --orphan gh-pages git rm -rf . 2>/dev/null || true fi # Restore plugins.json from safe location cp /tmp/plugins.json plugins.json git add plugins.json # Check if there are changes to commit if git diff --staged --quiet; then echo "No changes to commit" else git commit -m "Update plugins list [automated]" git push origin gh-pages fi