Skip to content

feat: add KubeStellar Console #7

feat: add KubeStellar Console

feat: add KubeStellar Console #7

Workflow file for this run

name: PR Validation
on:
pull_request_target:
types: [opened, edited, synchronize]
paths:
- 'README.md'
jobs:
validate-submission:
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v44
with:
files: README.md
- name: Extract new GitHub URLs from PR
id: extract-urls
if: steps.changed-files.outputs.any_changed == 'true'
run: |
# Get the diff and extract new GitHub repository URLs
git diff origin/${{ github.base_ref }}...HEAD -- README.md | \
grep -oP '^\+.*https://github\.com/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+' | \
grep -oP 'https://github\.com/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+' | \
sort -u > new_repos.txt
if [ -s new_repos.txt ]; then
echo "Found new repositories:"
cat new_repos.txt
echo "has_new_repos=true" >> $GITHUB_OUTPUT
else
echo "No new repositories found in this PR"
echo "has_new_repos=false" >> $GITHUB_OUTPUT
fi
- name: Check for duplicate tools
id: duplicate-check
if: steps.extract-urls.outputs.has_new_repos == 'true'
run: |
echo "## Duplicate Check" > duplicate_report.md
echo "" >> duplicate_report.md
DUPLICATES_FOUND=false
# Get the README from base branch
git show origin/${{ github.base_ref }}:README.md > base_readme.md
# Extract all existing GitHub URLs from base README
grep -oP 'https://github\.com/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+' base_readme.md | \
sort -u > existing_repos.txt
# Check each new repo against existing repos
while IFS= read -r new_repo; do
# Normalize URL (remove trailing slashes, lowercase)
NORMALIZED_NEW=$(echo "$new_repo" | sed 's|/$||' | tr '[:upper:]' '[:lower:]')
while IFS= read -r existing_repo; do
NORMALIZED_EXISTING=$(echo "$existing_repo" | sed 's|/$||' | tr '[:upper:]' '[:lower:]')
if [ "$NORMALIZED_NEW" = "$NORMALIZED_EXISTING" ]; then
echo "- :x: **Duplicate found:** \`$new_repo\` already exists in the list" >> duplicate_report.md
DUPLICATES_FOUND=true
break
fi
done < existing_repos.txt
done < new_repos.txt
if [ "$DUPLICATES_FOUND" = "true" ]; then
echo "" >> duplicate_report.md
echo "Please remove duplicate entries. Each tool should only appear once in the list." >> duplicate_report.md
echo "duplicates_found=true" >> $GITHUB_OUTPUT
else
echo ":white_check_mark: No duplicate tools found" >> duplicate_report.md
echo "duplicates_found=false" >> $GITHUB_OUTPUT
fi
cat duplicate_report.md
- name: Validate repositories
id: validate
if: steps.extract-urls.outputs.has_new_repos == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "## Repository Validation Report" > validation_report.md
echo "" >> validation_report.md
FAILED=false
WARNINGS=""
while IFS= read -r repo_url; do
# Extract owner/repo from URL
REPO_PATH=$(echo "$repo_url" | sed 's|https://github.com/||')
echo "Validating: $REPO_PATH"
echo "" >> validation_report.md
echo "### $REPO_PATH" >> validation_report.md
echo "" >> validation_report.md
# Fetch repository data from GitHub API
REPO_DATA=$(gh api "repos/$REPO_PATH" 2>/dev/null || echo "ERROR")
if [ "$REPO_DATA" = "ERROR" ]; then
echo "- :x: **Repository not found or inaccessible**" >> validation_report.md
FAILED=true
continue
fi
# Extract relevant fields
STARS=$(echo "$REPO_DATA" | jq -r '.stargazers_count')
CREATED_AT=$(echo "$REPO_DATA" | jq -r '.created_at')
PUSHED_AT=$(echo "$REPO_DATA" | jq -r '.pushed_at')
ARCHIVED=$(echo "$REPO_DATA" | jq -r '.archived')
LICENSE=$(echo "$REPO_DATA" | jq -r '.license.spdx_id // "None"')
DESCRIPTION=$(echo "$REPO_DATA" | jq -r '.description // "No description"')
HAS_README=$(echo "$REPO_DATA" | jq -r '.has_wiki')
FORK=$(echo "$REPO_DATA" | jq -r '.fork')
# Calculate ages in days
CREATED_TIMESTAMP=$(date -d "$CREATED_AT" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M:%SZ" "$CREATED_AT" +%s 2>/dev/null)
PUSHED_TIMESTAMP=$(date -d "$PUSHED_AT" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M:%SZ" "$PUSHED_AT" +%s 2>/dev/null)
NOW=$(date +%s)
REPO_AGE_DAYS=$(( (NOW - CREATED_TIMESTAMP) / 86400 ))
LAST_UPDATE_DAYS=$(( (NOW - PUSHED_TIMESTAMP) / 86400 ))
echo "| Check | Status | Value |" >> validation_report.md
echo "|-------|--------|-------|" >> validation_report.md
# Check 1: Repository age (must be > 30 days / 1 month)
if [ "$REPO_AGE_DAYS" -lt 30 ]; then
echo "| Repository Age | :x: FAIL | ${REPO_AGE_DAYS} days (minimum: 30 days) |" >> validation_report.md
FAILED=true
else
echo "| Repository Age | :white_check_mark: PASS | ${REPO_AGE_DAYS} days |" >> validation_report.md
fi
# Check 2: Minimum stars (must be >= 5)
if [ "$STARS" -lt 5 ]; then
echo "| Star Count | :x: FAIL | ${STARS} stars (minimum: 5) |" >> validation_report.md
FAILED=true
else
echo "| Star Count | :white_check_mark: PASS | ${STARS} stars |" >> validation_report.md
fi
# Check 3: Recent activity (updated within 365 days)
if [ "$LAST_UPDATE_DAYS" -gt 365 ]; then
echo "| Last Update | :x: FAIL | ${LAST_UPDATE_DAYS} days ago (maximum: 365 days) |" >> validation_report.md
FAILED=true
elif [ "$LAST_UPDATE_DAYS" -gt 180 ]; then
echo "| Last Update | :warning: WARNING | ${LAST_UPDATE_DAYS} days ago (possibly outdated) |" >> validation_report.md
WARNINGS="$WARNINGS\n- $REPO_PATH: Last updated $LAST_UPDATE_DAYS days ago"
else
echo "| Last Update | :white_check_mark: PASS | ${LAST_UPDATE_DAYS} days ago |" >> validation_report.md
fi
# Check 4: Not archived
if [ "$ARCHIVED" = "true" ]; then
echo "| Archived | :x: FAIL | Repository is archived |" >> validation_report.md
FAILED=true
else
echo "| Archived | :white_check_mark: PASS | Not archived |" >> validation_report.md
fi
# Check 5: Has license
if [ "$LICENSE" = "None" ] || [ "$LICENSE" = "null" ]; then
echo "| License | :x: FAIL | No license found |" >> validation_report.md
FAILED=true
else
echo "| License | :white_check_mark: PASS | $LICENSE |" >> validation_report.md
fi
# Check 6: Not a fork (warning only)
if [ "$FORK" = "true" ]; then
echo "| Fork Status | :warning: WARNING | This is a forked repository |" >> validation_report.md
WARNINGS="$WARNINGS\n- $REPO_PATH: Is a fork - please verify it's the canonical source"
else
echo "| Fork Status | :white_check_mark: PASS | Original repository |" >> validation_report.md
fi
# Check 7: Has description
if [ "$DESCRIPTION" = "No description" ] || [ -z "$DESCRIPTION" ]; then
echo "| Description | :warning: WARNING | No description provided |" >> validation_report.md
WARNINGS="$WARNINGS\n- $REPO_PATH: Missing repository description"
else
echo "| Description | :white_check_mark: PASS | Has description |" >> validation_report.md
fi
echo "" >> validation_report.md
done < new_repos.txt
# Add summary
echo "" >> validation_report.md
echo "---" >> validation_report.md
echo "" >> validation_report.md
if [ "$FAILED" = "true" ]; then
echo ":x: **Validation Failed**" >> validation_report.md
echo "" >> validation_report.md
echo "One or more repositories do not meet our contribution guidelines. Please review the requirements:" >> validation_report.md
echo "- Repository must be at least **1 month old**" >> validation_report.md
echo "- Repository must have at least **5 stars**" >> validation_report.md
echo "- Repository must have been updated within the last **12 months**" >> validation_report.md
echo "- Repository must not be archived" >> validation_report.md
echo "- Repository must have a recognized open-source license" >> validation_report.md
echo "validation_failed=true" >> $GITHUB_OUTPUT
else
echo ":white_check_mark: **All Validations Passed**" >> validation_report.md
echo "validation_failed=false" >> $GITHUB_OUTPUT
fi
if [ -n "$WARNINGS" ]; then
echo "" >> validation_report.md
echo "### Warnings" >> validation_report.md
echo -e "$WARNINGS" >> validation_report.md
fi
cat validation_report.md
- name: Check markdown format
id: format-check
if: steps.changed-files.outputs.any_changed == 'true'
run: |
echo "## Format Validation" > format_report.md
echo "" >> format_report.md
FORMAT_ISSUES=false
# Check for proper badge format in new lines
git diff origin/${{ github.base_ref }}...HEAD -- README.md | grep '^\+' | grep -v '^\+\+\+' > new_lines.txt || true
# Check each new tool entry for proper format
while IFS= read -r line; do
# Skip non-tool lines
if echo "$line" | grep -qP '^\+- \[.+\]\(https://'; then
# Check for Stars badge
if ! echo "$line" | grep -q 'img.shields.io/github/stars'; then
echo "- :x: Missing Stars badge: \`${line:0:60}...\`" >> format_report.md
FORMAT_ISSUES=true
fi
# Check for Last Commit badge
if ! echo "$line" | grep -q 'img.shields.io/github/last-commit'; then
echo "- :x: Missing Last Commit badge: \`${line:0:60}...\`" >> format_report.md
FORMAT_ISSUES=true
fi
# Check for description ending with period
if ! echo "$line" | grep -qP ' - .+\. !\['; then
echo "- :warning: Description may not end with period: \`${line:0:60}...\`" >> format_report.md
fi
fi
done < new_lines.txt
if [ "$FORMAT_ISSUES" = "true" ]; then
echo "" >> format_report.md
echo "Please ensure all tool entries follow the format:" >> format_report.md
echo "\`\`\`" >> format_report.md
echo '- [Tool Name](https://github.com/org/repo) - Description. ![Stars](https://img.shields.io/github/stars/org/repo) ![Last Commit](https://img.shields.io/github/last-commit/org/repo)' >> format_report.md
echo "\`\`\`" >> format_report.md
echo "format_failed=true" >> $GITHUB_OUTPUT
else
echo ":white_check_mark: Format validation passed" >> format_report.md
echo "format_failed=false" >> $GITHUB_OUTPUT
fi
cat format_report.md
- name: Post validation comment
if: steps.changed-files.outputs.any_changed == 'true'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
let comment = '## Automated PR Validation\n\n';
// Add duplicate report if exists
if (fs.existsSync('duplicate_report.md')) {
comment += fs.readFileSync('duplicate_report.md', 'utf8');
comment += '\n\n';
}
// Add validation report if exists
if (fs.existsSync('validation_report.md')) {
comment += fs.readFileSync('validation_report.md', 'utf8');
comment += '\n\n';
}
// Add format report if exists
if (fs.existsSync('format_report.md')) {
comment += fs.readFileSync('format_report.md', 'utf8');
}
comment += '\n\n---\n*This is an automated check. Maintainers will review your submission.*';
// Find existing bot comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(c =>
c.user.type === 'Bot' &&
c.body.includes('Automated PR Validation')
);
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: comment
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: comment
});
}
- name: Fail if validation failed
if: steps.duplicate-check.outputs.duplicates_found == 'true' || steps.validate.outputs.validation_failed == 'true' || steps.format-check.outputs.format_failed == 'true'
run: |
if [ "${{ steps.duplicate-check.outputs.duplicates_found }}" = "true" ]; then
echo "Duplicate tools found. Each tool should only appear once in the list."
fi
if [ "${{ steps.validate.outputs.validation_failed }}" = "true" ]; then
echo "Repository validation failed. Please review the requirements."
fi
if [ "${{ steps.format-check.outputs.format_failed }}" = "true" ]; then
echo "Format validation failed. Please fix the formatting issues."
fi
exit 1