Bläddra i källkod

Merge yappy_invaders from https://github.com/dagnazty/Yappy_Invaders

Willy-JL 1 år sedan
förälder
incheckning
ac8b9a684d

+ 1 - 0
yappy_invaders/.github/metrics.json

@@ -0,0 +1 @@
+{"stars": 3, "forks": 0, "followers": 2, "open_issues": 0, "closed_issues": 0}

+ 376 - 0
yappy_invaders/.github/workflows/github-metrics-notify.yml

@@ -0,0 +1,376 @@
+# .github/workflows/github-metrics-notify.yml
+
+name: GitHub Metrics Notification
+
+# Grants specific permissions to the GITHUB_TOKEN
+permissions:
+  contents: write         # Allows pushing changes to the repository
+  issues: read            # Optional: if you're interacting with issues
+  pull-requests: write    # Optional: if you're interacting with pull requests
+
+# Triggers the workflow on specific GitHub events and schedules it as a backup
+on:
+  # Trigger on repository star events
+  watch:
+    types: [started, deleted] # 'started' for star, 'deleted' for unstar
+
+  # Trigger on repository forks
+  fork:
+
+  # Trigger on issue events
+  issues:
+    types: [opened, closed, reopened, edited]
+
+  # Trigger on pull request events
+  pull_request:
+    types: [opened, closed, reopened, edited]
+
+  # Trigger on release events
+  release:
+    types: [published, edited, prereleased, released]
+
+  # Trigger on push events to the main branch
+  push:
+    branches:
+      - main
+
+  # Scheduled backup trigger every hour for followers/subscribers
+  schedule:
+    - cron: '0 */1 * * *' # Every hour at minute 0
+
+  # Allows manual triggering
+  workflow_dispatch:
+
+jobs:
+  notify_metrics:
+    runs-on: ubuntu-latest
+
+    steps:
+      # Step 1: Checkout the repository
+      - name: Checkout Repository
+        uses: actions/checkout@v3
+        with:
+          persist-credentials: true # Enables Git commands to use GITHUB_TOKEN
+          fetch-depth: 0            # Fetch all history for accurate metric tracking
+
+      # Step 2: Set Up Python Environment
+      - name: Set Up Python
+        uses: actions/setup-python@v4
+        with:
+          python-version: '3.x'     # Specify the Python version
+
+      # Step 3: Install Python Dependencies
+      - name: Install Dependencies
+        run: |
+          python -m pip install --upgrade pip
+          pip install requests
+
+      # Step 4: Fetch and Compare Metrics
+      - name: Fetch and Compare Metrics
+        id: fetch_metrics
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}               # Built-in secret provided by GitHub Actions
+          DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} # Your Discord webhook URL
+          GITHUB_EVENT_NAME: ${{ github.event_name }}             # To determine if run is manual or triggered by an event
+          GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} # Dynamic repository owner
+        run: |
+          python3 - <<'EOF' > fetch_metrics.out
+          import os
+          import requests
+          import json
+          from datetime import datetime
+
+          # Configuration
+          REPO_OWNER = os.getenv('GITHUB_REPOSITORY_OWNER')
+          REPO_NAME = os.getenv('GITHUB_REPOSITORY').split('/')[-1]
+          METRICS_FILE = ".github/metrics.json"
+
+          # Ensure .github directory exists
+          os.makedirs(os.path.dirname(METRICS_FILE), exist_ok=True)
+
+          # GitHub API Headers
+          headers = {
+              "Authorization": f"token {os.getenv('GITHUB_TOKEN')}",
+              "Accept": "application/vnd.github.v3+json"
+          }
+
+          # Function to fetch closed issues count using GitHub Search API
+          def fetch_closed_issues(owner, repo, headers):
+              search_api = f"https://api.github.com/search/issues?q=repo:{owner}/{repo}+type:issue+state:closed"
+              try:
+                  response = requests.get(search_api, headers=headers)
+                  response.raise_for_status()
+                  data = response.json()
+                  return data.get('total_count', 0)
+              except requests.exceptions.RequestException as e:
+                  print(f"Error fetching closed issues count: {e}")
+                  return 0
+
+          # Fetch current metrics from GitHub API
+          repo_api = f"https://api.github.com/repos/{REPO_OWNER}/{REPO_NAME}"
+
+          try:
+              response = requests.get(repo_api, headers=headers)
+              response.raise_for_status()
+              repo_data = response.json()
+              stars = repo_data.get('stargazers_count', 0)
+              forks = repo_data.get('forks_count', 0)
+              followers = repo_data.get('subscribers_count', 0)
+              open_issues = repo_data.get('open_issues_count', 0)
+              closed_issues = fetch_closed_issues(REPO_OWNER, REPO_NAME, headers)
+          except requests.exceptions.RequestException as e:
+              print(f"Error fetching repository data: {e}")
+              exit(1)
+
+          # Function to load previous metrics with error handling
+          def load_previous_metrics(file_path):
+              try:
+                  with open(file_path, 'r') as file:
+                      return json.load(file)
+              except json.decoder.JSONDecodeError:
+                  print("metrics.json is corrupted or empty. Reinitializing.")
+                  return {
+                      "stars": 0,
+                      "forks": 0,
+                      "followers": 0,
+                      "open_issues": 0,
+                      "closed_issues": 0
+                  }
+              except FileNotFoundError:
+                  return {
+                      "stars": 0,
+                      "forks": 0,
+                      "followers": 0,
+                      "open_issues": 0,
+                      "closed_issues": 0
+                  }
+
+          # Load previous metrics
+          prev_metrics = load_previous_metrics(METRICS_FILE)
+          is_initial_run = not os.path.exists(METRICS_FILE)
+
+          # Determine changes (both increases and decreases)
+          changes = {}
+          metrics = ["stars", "forks", "followers", "open_issues", "closed_issues"]
+          current_metrics = {
+              "stars": stars,
+              "forks": forks,
+              "followers": followers,
+              "open_issues": open_issues,
+              "closed_issues": closed_issues
+          }
+
+          for metric in metrics:
+              current = current_metrics.get(metric, 0)
+              previous = prev_metrics.get(metric, 0)
+              if current != previous:
+                  changes[metric] = current - previous
+
+          # Update metrics file
+          with open(METRICS_FILE, 'w') as file:
+              json.dump(current_metrics, file)
+
+          # Determine if a notification should be sent
+          event_name = os.getenv('GITHUB_EVENT_NAME')
+          send_notification = False
+          no_changes = False
+          initial_setup = False
+
+          if is_initial_run:
+              if event_name == 'workflow_dispatch':
+                  # Manual run: Send notification for initial setup
+                  send_notification = True
+                  initial_setup = True
+              elif event_name == 'watch' and changes.get('stars'):
+                  # Initial run triggered by a star event: Send notification
+                  send_notification = True
+              else:
+                  # Event-triggered runs: Do not send notification on initial setup
+                  send_notification = False
+          else:
+              if event_name == 'workflow_dispatch':
+                  # Manual run: Always send notification
+                  send_notification = True
+                  if not changes:
+                      no_changes = True
+              elif event_name == 'watch':
+                  # Star event: Send notification only if stars changed
+                  if changes.get('stars'):
+                      send_notification = True
+              else:
+                  # Scheduled run or other events: Send notification only if there are changes
+                  if changes:
+                      send_notification = True
+
+          if send_notification:
+              triggering_actor = os.getenv('GITHUB_ACTOR', 'Unknown')
+
+              # Prepare Discord notification payload
+              payload = {
+                  "embeds": [
+                      {
+                          "title": "📈 GitHub Repository Metrics Updated",
+                          "url": f"https://github.com/{REPO_OWNER}/{REPO_NAME}",  # Link back to the repository
+                          "color": 0x7289DA,  # Discord blurple color
+                          "thumbnail": {
+                              "url": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"  # GitHub logo
+                          },
+                          "fields": [
+                              {
+                                  "name": "📂 Repository",
+                                  "value": f"[{REPO_OWNER}/{REPO_NAME}](https://github.com/{REPO_OWNER}/{REPO_NAME})",
+                                  "inline": False
+                              },
+                              {
+                                  "name": "⭐ Stars",
+                                  "value": f"{stars}",
+                                  "inline": True
+                              },
+                              {
+                                  "name": "🍴 Forks",
+                                  "value": f"{forks}",
+                                  "inline": True
+                              },
+                              {
+                                  "name": "👥 Followers",
+                                  "value": f"{followers}",
+                                  "inline": True
+                              },
+                              {
+                                  "name": "🐛 Open Issues",
+                                  "value": f"{open_issues}",
+                                  "inline": True
+                              },
+                              {
+                                  "name": "🔒 Closed Issues",
+                                  "value": f"{closed_issues}",
+                                  "inline": True
+                              },
+                              {
+                                  "name": "👤 Triggered By",
+                                  "value": triggering_actor,
+                                  "inline": False
+                              },
+                          ],
+                          "footer": {
+                              "text": "GitHub Metrics Monitor",
+                              "icon_url": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"  # GitHub logo
+                          },
+                          "timestamp": datetime.utcnow().isoformat()  # Adds a timestamp to the embed
+                      }
+                  ]
+              }
+
+              if initial_setup:
+                  # Add a field indicating initial setup
+                  payload["embeds"][0]["fields"].append({
+                      "name": "⚙️ Initial Setup",
+                      "value": "Metrics tracking has been initialized.",
+                      "inline": False
+                  })
+              elif changes:
+                  # Add fields for each updated metric
+                  for metric, count in changes.items():
+                      emoji = {
+                          "stars": "⭐",
+                          "forks": "🍴",
+                          "followers": "👥",
+                          "open_issues": "🐛",
+                          "closed_issues": "🔒"
+                      }.get(metric, "")
+                      change_symbol = "+" if count > 0 else ""
+                      payload["embeds"][0]["fields"].append({
+                          "name": f"{emoji} {metric.replace('_', ' ').capitalize()} (Change)",
+                          "value": f"{change_symbol}{count}",
+                          "inline": True
+                      })
+              elif no_changes:
+                  # Indicate that there were no changes during a manual run
+                  payload["embeds"][0]["fields"].append({
+                      "name": "✅ No Changes",
+                      "value": "No updates to metrics since the last check.",
+                      "inline": False
+                  })
+
+              # Save payload to a temporary file for the next step
+              with open('payload.json', 'w') as f:
+                  json.dump(payload, f)
+
+              # Output whether to send notification
+              if initial_setup or changes or no_changes:
+                  print("SEND_NOTIFICATION=true")
+              else:
+                  print("SEND_NOTIFICATION=false")
+          else:
+              print("SEND_NOTIFICATION=false")
+          EOF
+
+      # Step 5: Ensure .gitignore Ignores Temporary Files
+      - name: Ensure .gitignore Ignores Temporary Files
+        run: |
+          # Check if .gitignore exists; if not, create it
+          if [ ! -f .gitignore ]; then
+            touch .gitignore
+          fi
+
+          # Add 'fetch_metrics.out' if not present
+          if ! grep -Fxq "fetch_metrics.out" .gitignore; then
+            echo "fetch_metrics.out" >> .gitignore
+            echo "Added 'fetch_metrics.out' to .gitignore"
+          else
+            echo "'fetch_metrics.out' already present in .gitignore"
+          fi
+
+          # Add 'payload.json' if not present
+          if ! grep -Fxq "payload.json" .gitignore; then
+            echo "payload.json" >> .gitignore
+            echo "Added 'payload.json' to .gitignore"
+          else
+            echo "'payload.json' already present in .gitignore"
+          fi
+
+      # Step 6: Decide Whether to Send Notification
+      - name: Check if Notification Should Be Sent
+        id: decide_notification
+        run: |
+            if grep -q "SEND_NOTIFICATION=true" fetch_metrics.out; then
+              echo "send=true" >> $GITHUB_OUTPUT
+            else
+              echo "send=false" >> $GITHUB_OUTPUT
+            fi
+        shell: bash
+
+      # Step 7: Send Discord Notification using curl
+      - name: Send Discord Notification
+        if: steps.decide_notification.outputs.send == 'true'
+        run: |
+          curl -H "Content-Type: application/json" -d @payload.json ${{ secrets.DISCORD_WEBHOOK_URL }}
+
+      # Step 8: Commit and Push Updated metrics.json and .gitignore
+      - name: Commit and Push Changes
+        if: steps.decide_notification.outputs.send == 'true'
+        run: |
+          git config --global user.name "GitHub Actions"
+          git config --global user.email "actions@github.com"
+          
+          # Stage metrics.json
+          git add .github/metrics.json
+          
+          # Stage .gitignore only if it was modified
+          if git diff --name-only | grep -q "^\.gitignore$"; then
+            git add .gitignore
+          else
+            echo ".gitignore not modified"
+          fi
+          
+          # Commit changes if there are any
+          git commit -m "Update metrics.json and ensure temporary files are ignored [skip ci]" || echo "No changes to commit"
+          
+          # Push changes to the main branch
+          git push origin main  # Replace 'main' with your default branch if different
+
+      # Step 9: Clean Up Temporary Files
+      - name: Clean Up Temporary Files
+        if: always()
+        run: |
+          rm -f fetch_metrics.out payload.json