-
Notifications
You must be signed in to change notification settings - Fork 92
Expand file tree
/
Copy pathvalidate-new-plugin-metadata.yml
More file actions
188 lines (163 loc) · 7.38 KB
/
validate-new-plugin-metadata.yml
File metadata and controls
188 lines (163 loc) · 7.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
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.sha }}
- 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