Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8e688b0
docs: add required file checks
Ang-dot Mar 5, 2025
ab4cd9c
docs: edit plugin_metadata_template.yml
Ang-dot Mar 5, 2025
68099db
refactor: beautify code
Ang-dot Mar 5, 2025
a4d6c29
chore: implement ci check to validate new plugin metadata
Ang-dot Mar 5, 2025
5b5738c
ci_test: changes for existing plugin
Ang-dot Mar 5, 2025
31f3c14
ci_test: no plugin_metadata.yml for new plugin
Ang-dot Mar 5, 2025
25eaa96
ci_test: empty plugin_metadata.yml for new plugin
Ang-dot Mar 5, 2025
f557cd9
ci_test: fill in plugin_name
Ang-dot Mar 5, 2025
f58d762
ci_test: fill in author
Ang-dot Mar 5, 2025
7a4bf21
ci_test: fill in short_description
Ang-dot Mar 5, 2025
2292447
ci_test: fill in detailed_description
Ang-dot Mar 5, 2025
454c65b
ci_test: fill in wrong release_date
Ang-dot Mar 6, 2025
bc689ab
ci_test: fill in release_date
Ang-dot Mar 6, 2025
5330324
ci_test: fill in wrong x_account_handle
Ang-dot Mar 6, 2025
39b7a96
ci_test: fill in x_account_handle
Ang-dot Mar 6, 2025
b227484
ci_test: fill in wrong support_contact
Ang-dot Mar 6, 2025
bd9ddc3
ci_test: fill in support_contact as email
Ang-dot Mar 6, 2025
5188f2e
ci_test: fill in support_contact as url
Ang-dot Mar 6, 2025
dda169b
ci_test: fill in wrong logo_url
Ang-dot Mar 6, 2025
512171a
ci_test: fill in logo_url
Ang-dot Mar 6, 2025
8aa181e
ci_test: fill in wrong plugin_logo_url
Ang-dot Mar 6, 2025
a5cac7a
ci_test: fill in plugin_logo_url
Ang-dot Mar 6, 2025
10c638c
ci_test: fill in wrong screenshots item
Ang-dot Mar 6, 2025
9fbaabb
ci_test: fill in screenshots item
Ang-dot Mar 6, 2025
a0a154a
ci_test: fill in wrong demo_video_url
Ang-dot Mar 6, 2025
f4f5a7a
ci_test: fill in demo_video_url
Ang-dot Mar 6, 2025
5682d78
ci_test: fill in wrong documentation url
Ang-dot Mar 6, 2025
74a9bbb
ci_test: fill in documentation url
Ang-dot Mar 6, 2025
5c4842d
ci_test: fill in wrong changelog url
Ang-dot Mar 6, 2025
58bc6f1
ci_test: fill in changelog url
Ang-dot Mar 6, 2025
55a6012
ci_test: fill in wrong community_url
Ang-dot Mar 6, 2025
1c9181d
ci_test: fill in community_url
Ang-dot Mar 6, 2025
cabb1a1
ci_test: add two new plugins in a pr
Ang-dot Mar 6, 2025
4f4cfc9
ci_test: add complete plugin_metadata.yml to new plugin folder
Ang-dot Mar 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE/plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ One-liner – What does this plugin contribution add or change?
## Plugin Documentation Checklist

- README Validation
- [ ] `README.md` file exists in the plugin root folder
- [ ] Clear installation instructions
- [ ] Usage examples with code snippets
- [ ] List of features and capabilities
- [ ] Troubleshooting guide (if applicable)
- [ ] Contribution guidelines (if applicable)

- Metadata Validation
- [ ] `plugin_metadata.yml` file exists in the plugin root folder
- [ ] Complete metadata provided in reference to [plugin metadata template](../.././plugins/plugin_metadata_template.yml)

## Dev Testing
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Auto Label PR
on:
pull_request:
branches: [ "main" ]
types: [opened, edited, reopened, synchronize]
types: [ opened, edited, reopened, synchronize ]

jobs:
label-plugin-pr:
Expand Down
188 changes: 188 additions & 0 deletions .github/workflows/validate-new-plugin-metadata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
name: Validate New Plugin Metadata

on:
pull_request:
branches: [ "main" ]
paths: [ "plugins/**" ]
types: [ opened, edited, reopened, synchronize ]

jobs:
identify-new-plugins:
runs-on: ubuntu-latest
outputs:
plugin_dirs: ${{ steps.find_new_plugins.outputs.plugin_dirs }}
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.ref }}

- name: Identify New Plugin Directories
id: find_new_plugins
run: |
# Fetch latest base branch state
git fetch origin ${{ github.event.pull_request.base.ref }}
BASE_COMMIT=$(git merge-base origin/${{ github.event.pull_request.base.ref }} HEAD)

# Find newly added plugin directories
NEW_PLUGINS=()
for plugin_dir in $(git diff --diff-filter=A --name-only $BASE_COMMIT...HEAD | grep '^plugins/' | cut -d'/' -f1-2 | sort -u); do
# Ensure directory is completely new (does not exist in base branch)
if ! git rev-parse --verify origin/${{ github.event.pull_request.base.ref }}:"$plugin_dir" &>/dev/null; then
NEW_PLUGINS+=("$plugin_dir")
fi
done

# Exit early if no new plugins were found
if [[ ${#NEW_PLUGINS[@]} -eq 0 ]]; then
echo "plugin_dirs=[]" >> $GITHUB_OUTPUT
exit 0
fi

# Convert plugin directory list to JSON format for use in next job
echo "plugin_dirs=$(jq -nc --argjson arr "$(printf '%s\n' "${NEW_PLUGINS[@]}" | jq -R . | jq -s .)" '$arr')" >> $GITHUB_OUTPUT

validate-individual-plugins:
needs: identify-new-plugins
if: ${{ needs.identify-new-plugins.outputs.plugin_dirs != '[]' }}
runs-on: ubuntu-latest
strategy:
matrix:
plugin_dir: ${{ fromJson(needs.identify-new-plugins.outputs.plugin_dirs) }}
steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Validate Plugin Metadata
run: |
set +e # Disable exit on error to allow all fields to be validated
metadata_file="${{ matrix.plugin_dir }}/plugin_metadata.yml"
if [[ ! -f "$metadata_file" ]]; then
echo "::error file=$metadata_file::Missing plugin_metadata.yml"
exit 1
fi

echo "::group::Validating $metadata_file"

metadata=$(yq '.' "$metadata_file")
errors=0

# Regex pattern for a valid URL
url_regex='^https?:\/\/[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(:[0-9]{1,5})?(\/.*)?$'
email_regex='^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
yyyy_mm_regex='^202[0-9]{1}-[0-9]{2}$'
x_account_handle_regex='^@[a-zA-Z0-9_]{1,15}$'

# Function to print missing field error
missing_field_error() {
local field="$1"
echo "::error file=$metadata_file::$field is required but missing"
((errors++))
}

# Function to check if a required field is missing
check_required_field() {
local field="$1"
local value=$(echo "$metadata" | yq -r ".${field}")
if [[ -z "$value" || "$value" == "null" ]]; then
missing_field_error "$field"
fi
}

# Function to validate a URL field (supports single values and arrays)
check_valid_url() {
local field="$1"
local required="${2:-optional}" # Default to "optional" if not specified
local value
local field_type
local non_empty_value=0

value=$(echo "$metadata" | yq -r ".${field}" 2>/dev/null || echo "")
field_type=$(echo "$metadata" | yq -r ".${field} | type" 2>/dev/null || echo "")

# If field is missing or empty
if [[ "$value" == "null" || -z "$value" ]]; then
if [[ "$required" == "required" ]]; then
missing_field_error "$field"
fi
return 0 # Skip validation if optional
fi

# Handle arrays of URLs
if [[ "$field_type" == "!!seq" ]]; then
mapfile -t urls < <(echo "$metadata" | yq -r ".${field} | .[]")

for url in "${urls[@]}"; do
[[ -z "$url" ]] && continue
if [[ ! "$url" =~ $url_regex ]]; then
echo "::error file=$metadata_file::'$field' contains an invalid URL: $url"
((errors++))
else
((non_empty_value++))
fi
done

if [[ $non_empty_value -eq 0 && "$required" == "required" ]]; then
echo "::error file=$metadata_file::'$field' is required but missing valid values"
((errors++))
fi
else
# Single value validation
if [[ ! "$value" =~ $url_regex ]]; then
echo "::error file=$metadata_file::'$field' is not a valid URL: $value"
((errors++))
fi
fi
}

# Validate required fields
check_required_field "plugin_name"
check_required_field "author"
check_required_field "short_description"
check_required_field "detailed_description"

# Validate URLs (optional fields but must be valid if provided, add "required" as second parameter to make them required, ie: check_valid_url "community_url" "required")
check_valid_url "logo_url"
check_valid_url "plugin_logo_url"
check_valid_url "demo_video_url"
check_valid_url "documentation_url"
check_valid_url "changelog_url"
check_valid_url "community_url"
check_valid_url "screenshots"

# Validate date format (YYYY-MM)
release_date=$(echo "$metadata" | yq -r '.release_date')
if [[ -z "$release_date" || "$release_date" == "null" ]]; then
missing_field_error "release_date"
else
if [[ ! "$release_date" =~ $yyyy_mm_regex ]]; then
echo "::error file=$metadata_file::'release_date' should be in YYYY-MM format"
((errors++))
fi
fi

# Validate X account handle format (@username)
x_account_handle=$(echo "$metadata" | yq '.x_account_handle')
if [[ -z "$x_account_handle" || "$x_account_handle" == "null" ]]; then
missing_field_error "x_account_handle"
else
if [[ -n "$x_account_handle" && ! "$x_account_handle" =~ $x_account_handle_regex ]]; then
echo "::error file=$metadata_file::'x_account_handle' is not a valid X (Twitter) handle"
((errors++))
fi
fi

# Validate support contact (must be a valid URL or email)
support_contact=$(echo "$metadata" | yq '.support_contact')
if [[ -z "$support_contact" || "$support_contact" == "null" ]]; then
missing_field_error "support_contact"
else
if [[ ! "$support_contact" =~ ($url_regex|$email_regex) ]]; then
echo "::error file=$metadata_file::'support_contact' must be a valid URL or email address"
((errors++))
fi
fi

echo "::endgroup::"
exit $errors
Empty file added plugins/allora/try_new_file.txt
Empty file.
23 changes: 23 additions & 0 deletions plugins/new_plugin/plugin_metadata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# General Information
plugin_name: "Plugin's Name"
author: "Plugin's Author"
logo_url: "https://i.imgur.com/dlq3ypk.png"
release_date: "2025-03"

# Description
short_description: "Plugin's short description"
detailed_description: "Plugin's detailed description"

# Media & Assets
plugin_logo_url: "https://i.imgur.com/dlq3ypk.png"
screenshots:
- "https://i.imgur.com/dlq3ypk.png"
- "https://i.imgur.com/dlq3ypk.png"
demo_video_url: "https://i.imgur.com/dlq3ypk.png"
documentation_url: "https://i.imgur.com/dlq3ypk.png"
changelog_url: "https://i.imgur.com/dlq3ypk.png"

# Contact & Support
x_account_handle: "@GAME_Virtuals"
support_contact: "https://discord.gg/virtualsio"
community_url: "https://discord.gg/virtualsio"
Empty file added plugins/new_plugin/test.txt
Empty file.
23 changes: 23 additions & 0 deletions plugins/new_plugin_2/plugin_metadata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# General Information
plugin_name: "Plugin's Name"
author: "Plugin's Author"
logo_url: "https://i.imgur.com/dlq3ypk.png"
release_date: "2025-03"

# Description
short_description: "Plugin's short description"
detailed_description: "Plugin's detailed description"

# Media & Assets
plugin_logo_url: "https://i.imgur.com/dlq3ypk.png"
screenshots:
- "https://i.imgur.com/dlq3ypk.png"
- "https://i.imgur.com/dlq3ypk.png"
demo_video_url: "https://i.imgur.com/dlq3ypk.png"
documentation_url: "https://i.imgur.com/dlq3ypk.png"
changelog_url: "https://i.imgur.com/dlq3ypk.png"

# Contact & Support
x_account_handle: "@GAME_Virtuals"
support_contact: "https://discord.gg/virtualsio"
community_url: "https://discord.gg/virtualsio"
Empty file added plugins/new_plugin_2/test.txt
Empty file.
12 changes: 6 additions & 6 deletions plugins/plugin_metadata_template.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
# General Information
plugin_name: "" # Name of the plugin
author: "" # Author and team name
logo_url: "" # URL to the author photo or team logo (512x512 recommended)
release_date: "" # Release date (DD-MM-YYYY)
logo_url: "" # URL to the author photo or team logo (512x512 recommended) (if any)
release_date: "" # Release date (YYYY-MM)

# Description
short_description: "" # One-liner description for listings
detailed_description: "" # Full description with features and benefits

# Media & Assets
plugin_logo_url: "" # URL to the plugin logo (512x512 recommended) (if any or fallback to logo_url)
screenshots: # List of screenshots showcasing the plugin
screenshots: # List of screenshots showcasing the plugin (if any)
- "" # e.g., "https://example.com/screenshot1.png"
- ""
demo_video_url: "" # Link to a demo or walkthrough video (if available)
documentation_url: "" # Link to the plugin's official documentation (if available)
demo_video_url: "" # Link to a demo or walkthrough video (if any)
documentation_url: "" # Link to the plugin's official documentation (if any)
changelog_url: "" # Link to the changelog (if maintained)

# Contact & Support
x_account_handle: "" # X (formerly known as Twitter) account handle (ie: @GAME_Virtuals)
support_contact: "" # Email or Slack/Discord link for user support
community_link: "" # Forum or community link (if any)
community_url: "" # Forum or community link (if any)