summaryrefslogtreecommitdiff
path: root/.github
diff options
context:
space:
mode:
Diffstat (limited to '.github')
-rw-r--r--.github/workflows/update-plugins-json.yml292
1 files changed, 292 insertions, 0 deletions
diff --git a/.github/workflows/update-plugins-json.yml b/.github/workflows/update-plugins-json.yml
new file mode 100644
index 000000000..570416103
--- /dev/null
+++ b/.github/workflows/update-plugins-json.yml
@@ -0,0 +1,292 @@
+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'
+ <?php
+ $content = file_get_contents($argv[1]);
+
+ // Use token_get_all to parse PHP code more reliably
+ $tokens = token_get_all($content);
+ $class_name = '';
+ $description = '';
+
+ // Find class declaration
+ for ($i = 0; $i < count($tokens); $i++) {
+ if (is_array($tokens[$i]) && $tokens[$i][0] === T_CLASS) {
+ // Skip whitespace
+ $j = $i + 1;
+ while ($j < count($tokens) && is_array($tokens[$j]) && $tokens[$j][0] === T_WHITESPACE) {
+ $j++;
+ }
+ // Get class name
+ if ($j < count($tokens) && is_array($tokens[$j]) && $tokens[$j][0] === T_STRING) {
+ $class_name = $tokens[$j][1];
+ break;
+ }
+ }
+ }
+
+ // Find about() function and extract description from return array
+ $in_about = false;
+ $in_return = false;
+ $array_depth = 0;
+ $strings = [];
+
+ for ($i = 0; $i < count($tokens); $i++) {
+ $token = $tokens[$i];
+
+ // Skip non-array tokens unless we're in return statement
+ if (!is_array($token)) {
+ if ($in_return) {
+ if ($token === '[') {
+ $array_depth++;
+ } elseif ($token === ']' || $token === ')') {
+ $array_depth--;
+ if ($array_depth === 0) {
+ break; // End of return array
+ }
+ }
+ }
+ 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 ($token[0] === T_CONSTANT_ENCAPSED_STRING) {
+ // This is a string literal
+ $str = $token[1];
+ // Remove quotes and decode
+ $str = substr($str, 1, -1);
+ $str = stripcslashes($str);
+ $strings[] = $str;
+ }
+ }
+ }
+
+ // Description is at index 1
+ if (isset($strings[1])) {
+ $description = $strings[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
+ 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, check it out
+ 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