Skip to content

Commit

Permalink
Add plugin dependency options and alias, use matrix for GitHub Actions
Browse files Browse the repository at this point in the history
  • Loading branch information
AbitTheGray committed Jun 19, 2024
1 parent ec965b6 commit 8002eef
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 37 deletions.
28 changes: 7 additions & 21 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,12 @@ name: Test behaviour
on: [push]

jobs:
minimal:
runs-on: ubuntu-latest
name: Minimal plugin.json
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Test minimal.json
id: plugin
uses: ./
with:
file: test/minimal.json

- name: Plugin info
shell: bash
run: |
echo "Codename: ${{steps.plugin.outputs.codename}}"
echo "Version: ${{steps.plugin.outputs.version}}"
full:
runs-on: ubuntu-latest
name: Full plugin.json
strategy:
matrix:
plugin_file: [ 'minimal.json', 'full.json' ]
name: ${{ matrix.plugin_file }}
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -33,10 +17,12 @@ jobs:
id: plugin
uses: ./
with:
file: test/full.json
file: 'test/${{ matrix.plugin_file }}'

- name: Plugin info
shell: bash
run: |
echo "Codename: ${{steps.plugin.outputs.codename}}"
echo "Version: ${{steps.plugin.outputs.version}}"
echo "Alias: ${{steps.plugin.outputs.alias}}"
echo "Other Plugins: ${{steps.plugin.outputs.other_plugins}}"
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,28 @@ Causes the validator to not check against official names.
Do not use this unless you are an official plugin.
It does not give you any advantage, just ignores checks for official-sounding names.

## Outputs

### `codename`

Parsed codename from the plugin.

### `version`

Parsed version from the plugin.

### `alias`

Comma-separated list of codenames.

### `depends`

Plugins this one directly depends on.

### `other_plugins`

Other plugins mentioned in plugin relations like `depends` or `recommends`.

## Example usage

```yaml
Expand Down
6 changes: 6 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ outputs:
description: 'Plugin codename'
version:
description: 'Plugin version'
alias:
description: 'Alternative plugin codenames separated by a comma'
depends:
description: 'Comma-separated plugins this one directly depends on'
other_plugins:
description: 'Comma-separated plugins mentioned in plugin relation fields'
runs:
using: 'node20'
main: 'index.js'
134 changes: 119 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,26 @@ function checkApiVersion(api_version)
break;
}
}
function checkCodename(codename)
function validateCodename(field, value)
{
if(typeof codename !== "string")
if(typeof value !== "string")
{
core.error("`codename` must be a string");
core.error(field + " must be a string");
return;
}

if(codename.length === 0)
if(value.length === 0)
{
core.error("`codename` cannot be empty");
core.error(field + " cannot be empty");
return;
}
else if(codename.length < 2)
else if(value.length < 2)
{
core.error("`codename` must be at least 2 characters");
core.error(field + " must be at least 2 characters");
return;
}
else if(codename.length < 8)
core.warning("`codename` should be at least 8 characters");
else if(value.length < 8)
core.warning(field + " should be at least 8 characters");

{
// - Only alphanumeric characters
Expand All @@ -56,19 +56,56 @@ function checkCodename(codename)
// - No number at the beginning (but may be at the end)
const regex_req = /^[a-zA-Z]([_a-zA-Z0-9]?[a-zA-Z0-9])*$/;
const regex_min = /^[a-z]([_a-z0-9]?[a-z0-9])*$/;
if(!regex_req.test(codename))
if(!regex_req.test(value))
{
core.error("`codename` does not match required format - only alphanumeric characters with optional underscore");
core.error(field + " does not match required format - only alphanumeric characters with optional underscore");
return;
}
else if(!regex_min.test(codename))
core.warning("`codename` does not match expected format - only lowercase letters, numbers and optional underscores");
else if(!regex_min.test(value))
core.warning(field + " does not match expected format - only lowercase letters, numbers and optional underscores");
}

if(codename.startsWith('vl_') || codename.startsWith('VL_') || codename.startsWith('voxelite_') || codename.startsWith('VOXELITE_'))
if(value.startsWith('vl_') || value.startsWith('VL_') || value.startsWith('voxelite_') || value.startsWith('VOXELITE_'))
{
if(!voxeliteOfficial)
core.warning("It looks like you are using `codename` similar to official Voxelite ones, please choose a different prefix");
core.warning("It looks like you are using " + field + " similar to official Voxelite ones, please choose a different prefix");
}
}
function checkCodename(codename)
{
validateCodename("`codename`", codename);
}
function checkAlias(alias)
{
validateCodename(`alias '${alias}'`, alias);
}
function checkAliases(alias)
{
switch(typeof alias)
{
case "string":
{
checkAlias(alias);
return [ alias ];
}
case "object":
{
if(Array.isArray(alias) && alias.every(item => typeof item === "string"))
{
alias.forEach(value => {
checkAlias(value);
});
return alias;
}
else
{
core.error("`alias` should be a string or an array");
return [];
}
}
default:
core.error("`alias` should be a string or an array");
return [];
}
}
function validateNonPrintCharacter(field, value)
Expand Down Expand Up @@ -288,6 +325,40 @@ function checkPermission(permission)
}
}
}
function checkPluginRelations(field, value, allowRelative)
{
if(typeof value == "object" && Object.keys(value).every(item => typeof item === "string") && Object.values(value).every(item => typeof item === "string"))
{
const versionRegex = /^([0-9]+(\.[0-9]+){0,2})?$/

let pluginNames = new Set();
Object.keys(value).forEach(key => {
let keyValue = value[key];

validateCodename(`${field} plugin`, key);
pluginNames.add(key);

// Validate version in `value` with `allowRelative` option
if(allowRelative)
{
if(keyValue.startsWith('<') || keyValue.startsWith('>') || keyValue.startsWith('='))
keyValue = keyValue.substring(1);
if(keyValue.startsWith('<=') || keyValue.startsWith('>='))
keyValue = keyValue.substring(2);
}
if(!versionRegex.test(keyValue))
core.error("Invalid version string: " + keyValue);

//TODO Check for colliding dependencies (same plugin but incompatible versions)
});
return pluginNames;
}
else
{
core.error(field + " plugin should be a string or an array");
return new Set();
}
}

try
{
Expand Down Expand Up @@ -322,6 +393,12 @@ try
checkCodename(json['codename']);
core.setOutput('codename', json['codename']);
}
// alias
if(json.hasOwnProperty("alias"))
{
const alias = checkAliases(json['alias']);
core.setOutput('alias', alias.join(','));
}
// version
if(!json.hasOwnProperty("version"))
core.error('Missing `version`');
Expand Down Expand Up @@ -365,6 +442,33 @@ try
else
console.error("Unsupported data type for `permissions` - use an array of strings")
}
// Relations with other plugins
{
let mentionedPlugins = new Set();
if(json.hasOwnProperty("depends"))
{
checkPluginRelations("`depends`", json["depends"], true).forEach(item => mentionedPlugins.add(item));
core.setOutput("depends", Array.from(mentionedPlugins).join(','));
}
if(json.hasOwnProperty("recommends"))
{
checkPluginRelations("`recommends`", json["recommends"], true).forEach(item => mentionedPlugins.add(item));
}
if(json.hasOwnProperty("suggests"))
{
checkPluginRelations("`suggests`", json["suggests"], true).forEach(item => mentionedPlugins.add(item));
}
if(json.hasOwnProperty("breaks"))
{
checkPluginRelations("`breaks`", json["breaks"], true).forEach(item => mentionedPlugins.add(item));
}
if(json.hasOwnProperty("replaces"))
{
checkPluginRelations("`replaces`", json["replaces"], false).forEach(item => mentionedPlugins.add(item));
}

core.setOutput("other_plugins", Array.from(mentionedPlugins).join(','));
}
}
}
);
Expand Down
21 changes: 20 additions & 1 deletion test/full.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
{
"api_version": 1,
"codename": "full_plugin",
"name": "Full Plugin",
"alias": [ "plugin_full", "full_example_plugin" ],
"name": "Full Example Plugin",
"description": "Example for all available fields in Voxelite's plugin.json",
"version": "0.1.0",
"author": [ "me", "myself", "and I" ],
"website": "https://example.com",
"depends": {
"a": ">=1.0",
"b": "<1.2.3"
},
"recommends": {
"a": ">=1.1"
},
"suggests": {
"a": ">=1.2",
"c": ">2"
},
"breaks": {
"ac": ">=1.0"
},
"replaces": {
"zzz": "",
"abc": "1.2"
},
"permissions": [
"network.http",
"lua_sandbox",
Expand Down

0 comments on commit 8002eef

Please sign in to comment.