Skip to content

Commit 40e22a0

Browse files
authored
Allow to submit extension updates (#1908)
- Don't show in changelog
1 parent 74974d2 commit 40e22a0

File tree

11 files changed

+263
-142
lines changed

11 files changed

+263
-142
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: 🔄Extension update
2+
description: Submit an extension update
3+
title: 'Extension update: <title>'
4+
labels: [🔄 Extension update]
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: '# Extension update submission'
9+
- type: textarea
10+
id: description
11+
attributes:
12+
label: Changes
13+
description: Describe the features you added or the bugs you fixed.
14+
placeholder: This update adds...
15+
- type: textarea
16+
id: how-to
17+
attributes:
18+
label: How to use the new features
19+
description: Describe how your new features can be used.
20+
placeholder: If you put behavior X on a sprite, you can make a...
21+
- type: checkboxes
22+
id: checklist
23+
attributes:
24+
label: Checklist
25+
description: Make sure you have done all of this before submitting!
26+
options:
27+
- label: "I've followed all of [the best practices](http://wiki.compilgames.net/doku.php/gdevelop5/extensions/best-practices)."
28+
required: true
29+
- label: I confirm that this extension can be integrated to this GitHub repository, distributed and MIT licensed.
30+
required: true
31+
- label: I am aware that the extension may be updated by anyone, and do not need my explicit consent to do so.
32+
required: true
33+
- type: textarea
34+
id: example
35+
attributes:
36+
label: Example file
37+
description: Please drag and drop an example project using your extension, compressed in a ZIP file, into this text field. **DO NOT PUT A LINK TO AN EXTERNAL SERVICE LIKE GOOGLE DRIVE!**
38+
placeholder: '[MyExample.zip]()'
39+
validations:
40+
required: true
41+
- type: textarea
42+
id: extension
43+
attributes:
44+
label: Extension file
45+
description: Please drag and drop your extension JSON file, compressed in a ZIP file, into this text field. **DO NOT PUT A LINK TO AN EXTERNAL SERVICE LIKE GOOGLE DRIVE!**
46+
placeholder: '[MyExtension.json.zip]()'
47+
validations:
48+
required: true
49+
- type: markdown
50+
attributes:
51+
value: |
52+
You also may have to create an account on GitHub before posting.
53+
Your extension will be added to the list after we have checked that it contains no virus and respects the best practices.
54+
Thanks for contributing to GDevelop! 🙌

.github/ISSUE_TEMPLATE/new-extension.yml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,6 @@ body:
3030
required: true
3131
- label: I am aware that the extension may be updated by anyone, and do not need my explicit consent to do so.
3232
required: true
33-
- type: dropdown
34-
id: tier
35-
attributes:
36-
label: 'What tier of review do you aim for your extension?'
37-
description: '[More information](https://wiki.gdevelop.io/gdevelop5/extensions/tiers)'
38-
options:
39-
- Community (Unreviewed)
40-
- Reviewed
41-
validations:
42-
required: true
4333
- type: textarea
4434
id: example
4535
attributes:

.github/workflows/auto-pr.yml

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ jobs:
2727
const { extractExtension } = require('./scripts/extract-extension.js');
2828
const { verifyExtension } = require('./scripts/check-single-extension.js')
2929
30-
31-
const { error, extensionName } = await extractExtension("/tmp/ext.zip");
30+
const isUpdate = ${{ contains(github.event.issue.labels.*.name, '🔄 Extension update') }};
31+
const { error, extensionName, tier } = await extractExtension("/tmp/ext.zip", { isUpdate });
3232
3333
if(error === "zip-error")
3434
github.rest.issues.createComment({
@@ -62,6 +62,14 @@ jobs:
6262
body: `👋 Hey @${{ github.event.issue.user.login }}, thanks for your submission! We are sorry, but the filename of the extension has unrecognized characters. Since filenames with non latin characters ("ASCII") can cause issues, our system won't allow file names with other characters than latin upper- and lowercase characters or numbers. Additionally, the first character must be an uppercase character. Please update your original submission post with a new zip file containing your extension with another file name following those guidelines 🙏`
6363
})
6464
65+
if(error === "nothing-to-update")
66+
github.rest.issues.createComment({
67+
issue_number: context.issue.number,
68+
owner: context.repo.owner,
69+
repo: context.repo.repo,
70+
body: `👋 Hey @${{ github.event.issue.user.login }}, thanks for your submission! We are sorry, but the name of the extension you submitted for an update doesn't match any existing extension. If you want to update one of your ingoing extension submission, please follow the instruction on your first submission 🙏`
71+
})
72+
6573
if(error) {
6674
core.setFailed("Extraction of the extension failed!");
6775
return;
@@ -90,7 +98,7 @@ jobs:
9098
issue_number: context.issue.number,
9199
owner: context.repo.owner,
92100
repo: context.repo.repo,
93-
body: `👋 Hey @${{ github.event.issue.user.login }}, thanks for your submission! We are sorry, but it seems we already have a reviewed extension with that name. Extensions cannot be in both the community and reviewed extensions list at once. If you are trying to update that extension, please ask a member of the extension team for help. If the name clash is a coincidence, please update your original submission post with a new zip file containing your extension with a file name that is not already taken 🙏`
101+
body: `👋 Hey @${{ github.event.issue.user.login }}, thanks for your submission! We are sorry, but it seems we already have a reviewed extension with that name. Extensions cannot be in both the experimental and reviewed extensions list at once. If you are trying to update that extension, please ask a member of the extension team for help. If the name clash is a coincidence, please update your original submission post with a new zip file containing your extension with a file name that is not already taken 🙏`
94102
})
95103
96104
if(code === "invalid-json")
@@ -106,27 +114,36 @@ jobs:
106114
issue_number: context.issue.number,
107115
owner: context.repo.owner,
108116
repo: context.repo.repo,
109-
body: `👋 Hey ${{ github.event.issue.user.login }}, thanks for your submission! It would seem you confused the extension file with your project file, and thus we cannot find your extension. Make sure you exported the extension itself from the extension editor as a standalone file, zip that standalone extension file, and make sure you did not confuse the "Example" and "Extension" fields while submitting!`
117+
body: `👋 Hey @${{ github.event.issue.user.login }}, thanks for your submission! It would seem you confused the extension file with your project file, and thus we cannot find your extension. Make sure you exported the extension itself from the extension editor as a standalone file, zip that standalone extension file, and make sure you did not confuse the "Example" and "Extension" fields while submitting!`
110118
})
111119
112120
if(code === "unknown-json-contents")
113121
github.rest.issues.createComment({
114122
issue_number: context.issue.number,
115123
owner: context.repo.owner,
116124
repo: context.repo.repo,
117-
body: `👋 Hey ${{ github.event.issue.user.login }}, thanks for your submission! It would seem your JSON file is not a valid GDevelop extension, although it is a JSON file. Please make sure you are exporting with the latest version of GDevelop and that you are not modifying the JSON incorrectly after the export.`
125+
body: `👋 Hey @${{ github.event.issue.user.login }}, thanks for your submission! It would seem your JSON file is not a valid GDevelop extension, although it is a JSON file. Please make sure you are exporting with the latest version of GDevelop and that you are not modifying the JSON incorrectly after the export.`
118126
})
119127
120128
if(code === "rule-break")
121129
github.rest.issues.createComment({
122130
issue_number: context.issue.number,
123131
owner: context.repo.owner,
124132
repo: context.repo.repo,
125-
body: `👋 Hey ${{ github.event.issue.user.login }}, thanks for your submission! Unfortunately, all submitted extensions have to meet some minimal quality standard - the extension best practices - and our system has found that your extension does not fully comply 😔. You can find all of those rules on [the GDevelop wiki](https://wiki.gdevelop.io/gdevelop5/extensions/best-practices). \n\nThe following issues have been found by the system concerning the respect of those best practices by your extension: \n\`\`\`\n${errors.reduce((acc, error) => `${acc}\n ⟶ ❌ ${error}`, '').slice(1)}\n\`\`\`\nPlease update your original submission post with a new zip file containing your extensions updated to follow those guidelines 🙏`
133+
body: `👋 Hey @${{ github.event.issue.user.login }}, thanks for your submission! Unfortunately, all submitted extensions have to meet some minimal quality standard - the extension best practices - and our system has found that your extension does not fully comply 😔. You can find all of those rules on [the GDevelop wiki](https://wiki.gdevelop.io/gdevelop5/extensions/best-practices). \n\nThe following issues have been found by the system concerning the respect of those best practices by your extension: \n\`\`\`\n${errors.reduce((acc, error) => `${acc}\n ⟶ ❌ ${error}`, '').slice(1)}\n\`\`\`\nPlease update your original submission post with a new zip file containing your extensions updated to follow those guidelines 🙏`
126134
})
127135
128136
if(code !== "success") core.setFailed("Verification of the extension failed!");
129137
138+
if (isUpdate) {
139+
github.rest.issues.addLabels({
140+
issue_number: context.issue.number,
141+
owner: context.repo.owner,
142+
repo: context.repo.repo,
143+
labels: [tier === 'reviewed' ? '🔍 Reviewed extension' : '🧪 Experimental extension']
144+
})
145+
}
146+
130147
- name: Create Pull Request
131148
id: cpr
132149
uses: peter-evans/create-pull-request@v5
@@ -161,7 +178,7 @@ jobs:
161178
162179
It can take a few seconds for the file to fully upload and show as the above. Once it is like shown above,
163180
click "Comment" and let the bot do the rest!
164-
labels: ✨ New extension
181+
labels: ${{github.event.issue.labels}}
165182

166183
- name: Add card to pending review
167184
uses: peter-evans/create-or-update-project-card@v2
@@ -175,4 +192,4 @@ jobs:
175192
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
176193
run: |
177194
gh issue close ${{ github.event.issue.number }}
178-
gh issue comment ${{ github.event.issue.number }} --body "Hi @${{ github.event.issue.user.login }}! 👋 This submission has passed all required tests, and has been moved to a PR as part of our submission pipeline. [You can see the progress of your submission on this page](${{ steps.cpr.outputs.pull-request-url }}). Community submissions are not reviewed by default, so your extension should be added once we've checked that your submission doesn't contain malicious code without further intervention on your part. If you wish for your extension to be reviewed (and thereby moved to the list of reviewed extensions), please follow the instructions written on the [README](https://github.com/GDevelopApp/GDevelop-extensions#get-your-extension-reviewed-extensions). Thanks again for your contribution to GDevelop!"
195+
gh issue comment ${{ github.event.issue.number }} --body "Hi @${{ github.event.issue.user.login }}! 👋 This submission has passed all preliminary tests, and has been moved to a PR where the review will be done. [You can see the progress and update your submission on this page](${{ steps.cpr.outputs.pull-request-url }}). Thanks again for your contribution to GDevelop!"

.github/workflows/commands.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ jobs:
7575
run: |
7676
FILEURL=$(echo $BODY | grep -ioEh 'https?://\S+.zip' -m1)
7777
curl -L $FILEURL -o /tmp/ext.zip
78-
unzip -o /tmp/ext.zip -d ./extensions/community
78+
unzip -o /tmp/ext.zip -d ./extensions/${{ contains(github.event.issue.labels.*.name, '🔍 Reviewed extension') && 'reviewed' || 'community' }}
7979
8080
- name: Rebuild the database
8181
run: |

__tests__/auto-pr/auto-pr.spec.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@ const TEMPORARY_MOCK_EXTENSIONS_FOLDER = __dirname + '/mock_extensions_folder';
66
const TEST_ZIPS_FOLDER = __dirname + '/test-zips';
77
const TEST_EXTENSIONS_FOLDER = __dirname + '/test-extensions';
88

9-
/** @param {string} zipName */
10-
const wrappedExtractExtension = async (zipName) =>
9+
/**
10+
* @param {string} zipName
11+
* @param {boolean | undefined} isUpdate
12+
*/
13+
const wrappedExtractExtension = async (zipName, isUpdate = false) =>
1114
(
12-
await extractExtension(
13-
`${TEST_ZIPS_FOLDER}/${zipName}.zip`,
14-
TEMPORARY_MOCK_EXTENSIONS_FOLDER
15-
)
15+
await extractExtension(`${TEST_ZIPS_FOLDER}/${zipName}.zip`, {
16+
extensionsFolder: TEMPORARY_MOCK_EXTENSIONS_FOLDER,
17+
isUpdate,
18+
})
1619
).error;
1720

1821
/** @param {string} extensionName */
@@ -45,7 +48,13 @@ describe('Auto-pr pipeline', () => {
4548
'too-many-files'
4649
);
4750

48-
expect(await wrappedExtractExtension(`valid-extension`)).toBeUndefined();
51+
expect(await wrappedExtractExtension(`new-extension`)).toBeUndefined();
52+
expect(await wrappedExtractExtension(`experimental-update`)).toBeUndefined();
53+
expect(await wrappedExtractExtension(`reviewed-update`)).toBeUndefined();
54+
55+
expect(await wrappedExtractExtension(`new-extension`, true)).toBe('nothing-to-update');
56+
expect(await wrappedExtractExtension(`experimental-update`, true)).toBeUndefined();
57+
expect(await wrappedExtractExtension(`reviewed-update`, true)).toBeUndefined();
4958
});
5059

5160
test(`verifyExtension()`, async () => {
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
{
2+
"author": "Arthur Pacaud (arthuro555)",
3+
"description": "Prevents the back button from quitting the game and provides a condition to check when it's pressed (to allow customising its behavior).",
4+
"extensionNamespace": "",
5+
"fullName": "Back button",
6+
"helpPath": "",
7+
"iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLWtleWJvYXJkLWJhY2tzcGFjZSIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0yMSwxMUg2LjgzTDEwLjQxLDcuNDFMOSw2TDMsMTJMOSwxOEwxMC40MSwxNi41OEw2LjgzLDEzSDIxVjExWiIgLz48L3N2Zz4=",
8+
"name": "BackButton",
9+
"previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/keyboard-backspace.svg",
10+
"shortDescription": "Adds interactions with the back button.",
11+
"version": "1.0.0",
12+
"tags": [
13+
"back",
14+
"mobile",
15+
"button",
16+
"input"
17+
],
18+
"authorIds": [
19+
"ZgrsWuRTAkXgeuPV9bo0zuEcA2w1"
20+
],
21+
"dependencies": [],
22+
"eventsFunctions": [
23+
{
24+
"description": "",
25+
"fullName": "",
26+
"functionType": "Action",
27+
"name": "onFirstSceneLoaded",
28+
"private": false,
29+
"sentence": "",
30+
"events": [
31+
{
32+
"disabled": false,
33+
"folded": false,
34+
"type": "BuiltinCommonInstructions::JsCode",
35+
"inlineCode": "gdjs.evtTools.back_button = {\n triggered: false,\n _popStateListener: (event) => {\n gdjs.evtTools.back_button.triggered = true;\n history.pushState(\"\", \"\"); // Push a new fake state as the old one was popped\n }\n};\n\n// Handle back button on the web\nhistory.pushState(\"\", \"\"); // Push a fake state to prevent switching page when clicking on back\nwindow.addEventListener('popstate', gdjs.evtTools.back_button._popStateListener);\n\n// Handle back button on cordova\ndocument.addEventListener(\"backbutton\", e => {\n e.preventDefault();\n gdjs.evtTools.back_button.triggered = true;\n}, false); \n",
36+
"parameterObjects": "",
37+
"useStrict": true,
38+
"eventsSheetExpanded": false
39+
}
40+
],
41+
"parameters": [],
42+
"objectGroups": []
43+
},
44+
{
45+
"description": "Triggers whenever the player presses the back button.",
46+
"fullName": "Back button is pressed",
47+
"functionType": "Condition",
48+
"name": "onBackButtonPressed",
49+
"private": false,
50+
"sentence": "Back button is pressed",
51+
"events": [
52+
{
53+
"disabled": false,
54+
"folded": false,
55+
"type": "BuiltinCommonInstructions::JsCode",
56+
"inlineCode": "eventsFunctionContext.returnValue = gdjs.evtTools.back_button.triggered;\n",
57+
"parameterObjects": "",
58+
"useStrict": true,
59+
"eventsSheetExpanded": false
60+
}
61+
],
62+
"parameters": [],
63+
"objectGroups": []
64+
},
65+
{
66+
"description": "This simulates the normal action of the back button. \nThis action will quit the app when in a mobile app, and go back to the previous page when in a web browser.",
67+
"fullName": "Trigger back button",
68+
"functionType": "Action",
69+
"name": "doDefault",
70+
"private": false,
71+
"sentence": "Simulate back button press",
72+
"events": [
73+
{
74+
"disabled": false,
75+
"folded": false,
76+
"type": "BuiltinCommonInstructions::JsCode",
77+
"inlineCode": "// Close the app on cordova, as this is the default behavior\nif (navigator.app) {\n navigator.app.exitApp();\n} else if (navigator.device && navigator.device.exitApp) {\n navigator.device.exitApp();\n} else {\n // Go to previous page as it is the default on browsers\n // Remove the listener so new fake states don't get pushed\n window.removeEventListener('popstate', gdjs.evtTools.back_button._popStateListener);\n history.back(); // Remove the state that prevents going back\n history.back(); // Actually go back\n}\n",
78+
"parameterObjects": "",
79+
"useStrict": true,
80+
"eventsSheetExpanded": false
81+
}
82+
],
83+
"parameters": [],
84+
"objectGroups": []
85+
},
86+
{
87+
"description": "",
88+
"fullName": "",
89+
"functionType": "Action",
90+
"name": "onScenePostEvents",
91+
"private": false,
92+
"sentence": "",
93+
"events": [
94+
{
95+
"disabled": false,
96+
"folded": false,
97+
"type": "BuiltinCommonInstructions::JsCode",
98+
"inlineCode": "gdjs.evtTools.back_button.triggered = false;\n",
99+
"parameterObjects": "",
100+
"useStrict": true,
101+
"eventsSheetExpanded": false
102+
}
103+
],
104+
"parameters": [],
105+
"objectGroups": []
106+
}
107+
],
108+
"eventsBasedBehaviors": []
109+
}
1.82 KB
Binary file not shown.
1.57 KB
Binary file not shown.
File renamed without changes.

0 commit comments

Comments
 (0)