Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 8 additions & 6 deletions .github/PULL_REQUEST_TEMPLATE/plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ One-liner – What does this plugin contribution add or change?
## Plugin Documentation Checklist

- README Validation
- [ ] Clear installation instructions
- [ ] Usage examples with code snippets
- [ ] List of features and capabilities
- [ ] Troubleshooting guide (if applicable)
- [ ] Contribution guidelines (if applicable)
- [ ] `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
- [ ] Complete metadata provided in reference to [plugin metadata template](../.././plugins/plugin_metadata_template.yml)
- [ ] `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, optional by default, add "required" as second parameter to make it required, ie: check_valid_url "community_url" "required")
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
32 changes: 23 additions & 9 deletions CONTRIBUTION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,35 @@ There are various ways you can contribute to the GAME SDK, whether it's fixing b
1. **Fork** the repository and clone it to your local machine.
2. **Create a Branch** for your changes.
3. **Make Changes** to address the issue or add the feature.
4. **Commit** with a message that clearly explains your change.
5. **Push** the branch to your fork and submit a pull request.
6. **Label** the pull request appropriately based on the [label definitions](#label-definitions)

4. **Ensure Compliance** with the relevant contribution requirements:
- For **general PRs**, follow the [default PR template](./.github/PULL_REQUEST_TEMPLATE/default.md).
- For **plugin contributions**, ensure your PR follows the [plugin PR template](./.github/PULL_REQUEST_TEMPLATE/plugin.md).
5. **Commit** with a message that clearly explains your change.
6. **Push** the branch to your fork and submit a pull request.
7. **Label** the pull request appropriately based on the [label definitions](#label-definitions).

### Plugin Contribution Guidelines
If you are adding a new plugin, ensure the following:
- A `README.md` file exists in the plugin root directory and includes:
- Installation instructions
- Usage examples with code snippets
- List of features and capabilities
- Troubleshooting guide (if applicable)
- Contribution guidelines (if applicable)
- A `plugin_metadata.yml` file exists in the plugin root directory with complete metadata as per the [plugin metadata template](./plugins/plugin_metadata_template.yml).
- Your PR follows the [plugin PR template](./.github/PULL_REQUEST_TEMPLATE/plugin.md).
- Screenshots, video demonstrations, or logs showcasing the plugin functionality are included (if applicable).

### Reporting Bugs
- Open an issue in the [Issues](https://github.com/game-by-virtuals/game-python/issues) tab and tag it as a `bug`.
- Open an issue in the [Issues](https://github.com/game-by-virtuals/game-node/issues) tab and tag it as a `bug`.

### Suggesting Enhancements
- Open an issue in the [Issues](https://github.com/your-username/my-project/issues) tab and tag it as an `enhancement`.
- Open an issue in the [Issues](https://github.com/game-by-virtuals/game-node/issues) tab and tag it as an `enhancement`.

## Label Definitions

Please tag issues and pull requests appropriately, based on the definition below:
- **plugin**: A plugin contribution.
- **bug**: A problem that needs fixing.
- **enhancement**: A requested enhancement.
- **help wanted**: A task that is open for anyone to work on.
- **documentation**: Documentation changes.
- **documentation**: Documentation changes.
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)