cloudron 5.11.7 → 5.11.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cloudron-appstore +4 -0
- package/bin/cloudron-build +1 -0
- package/package.json +3 -3
- package/src/appstore-actions.js +77 -3
- package/src/build-actions.js +11 -3
package/bin/cloudron-appstore
CHANGED
|
@@ -34,6 +34,10 @@ program.command('approve')
|
|
|
34
34
|
.option('--appstore-id <appid@version>', 'Appstore id and version')
|
|
35
35
|
.action(appstoreActions.approve);
|
|
36
36
|
|
|
37
|
+
program.command('notify')
|
|
38
|
+
.description('Notify forum about successful app submission')
|
|
39
|
+
.action(appstoreActions.notify);
|
|
40
|
+
|
|
37
41
|
program.command('tag <version>')
|
|
38
42
|
.description('Tag the repo')
|
|
39
43
|
.action(appstoreActions.tag);
|
package/bin/cloudron-build
CHANGED
|
@@ -45,6 +45,7 @@ program.command('push')
|
|
|
45
45
|
.option('--id <buildid>', 'Build ID')
|
|
46
46
|
.option('--repository [repository url]', 'Set repository to push to. e.g registry/username/projectname')
|
|
47
47
|
.option('--tag <docker image tag>', 'Docker image tag. Note that this does not include the repository name')
|
|
48
|
+
.option('--image <docker image>', 'Docker image of the form registry/repo:tag')
|
|
48
49
|
.action(buildActions.push);
|
|
49
50
|
|
|
50
51
|
program.command('status')
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloudron",
|
|
3
|
-
"version": "5.11.
|
|
3
|
+
"version": "5.11.8",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Cloudron Commandline Tool",
|
|
6
6
|
"main": "main.js",
|
|
7
|
-
"homepage": "https://git.cloudron.io/
|
|
7
|
+
"homepage": "https://git.cloudron.io/platform/cloudron-cli",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://git.cloudron.io/
|
|
10
|
+
"url": "https://git.cloudron.io/platform/cloudron-cli.git"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"test": "mocha test/test.js"
|
package/src/appstore-actions.js
CHANGED
|
@@ -25,7 +25,8 @@ exports = module.exports = {
|
|
|
25
25
|
revoke,
|
|
26
26
|
approve,
|
|
27
27
|
|
|
28
|
-
tag
|
|
28
|
+
tag,
|
|
29
|
+
notify
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
const NO_MANIFEST_FOUND_ERROR_STRING = 'No CloudronManifest.json found';
|
|
@@ -280,8 +281,19 @@ async function upload(localOptions, cmd) {
|
|
|
280
281
|
const appConfig = config.getAppConfig(sourceDir);
|
|
281
282
|
|
|
282
283
|
// image can be passed in options for buildbot
|
|
283
|
-
|
|
284
|
-
|
|
284
|
+
if (options.image) {
|
|
285
|
+
manifest.dockerImage = options.image;
|
|
286
|
+
} else {
|
|
287
|
+
const gitCommit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();
|
|
288
|
+
if (appConfig.gitCommit !== gitCommit) {
|
|
289
|
+
console.log(`This build ${appConfig.dockerImage} was made from git hash ${appConfig.gitCommit} but you are now at ${gitCommit}`);
|
|
290
|
+
if (!appConfig.gitCommit) return exit('The build is stale');
|
|
291
|
+
const output = execSync(`git diff ${appConfig.gitCommit}..HEAD --name-only`, { encoding: 'utf8'});
|
|
292
|
+
const changedFiles = output.trim().split('\n').filter(filepath => !filepath.match(/(^CHANGELOG|README|CloudronManifest|test\|.git|screenshots|renovate|LICENSE|POSTINSTALL|.docker|logo)/));
|
|
293
|
+
if (changedFiles.length) return exit(`The build is stale. Changed files: ${changedFiles.join(',')}`);
|
|
294
|
+
}
|
|
295
|
+
manifest.dockerImage = appConfig.dockerImage;
|
|
296
|
+
}
|
|
285
297
|
|
|
286
298
|
if (!manifest.dockerImage) exit('No docker image found, run `cloudron build` first');
|
|
287
299
|
|
|
@@ -291,6 +303,10 @@ async function upload(localOptions, cmd) {
|
|
|
291
303
|
const error = manifestFormat.checkAppstoreRequirements(manifest);
|
|
292
304
|
if (error) return exit(error);
|
|
293
305
|
|
|
306
|
+
const [repo, tag] = manifest.dockerImage.split(':');
|
|
307
|
+
const [tagError, tagResponse] = await safe(superagent.get(`https://hub.docker.com/v2/repositories/${repo}/tags/${tag}`).ok(() => true));
|
|
308
|
+
if (tagError || tagResponse.statusCode !== 200) return exit(`Failed to find docker image in dockerhub. check https://hub.docker.com/r/${repo}/tags : ${requestError(tagResponse)}`);
|
|
309
|
+
|
|
294
310
|
// ensure the app is known on the appstore side
|
|
295
311
|
const baseDir = path.dirname(manifestFilePath);
|
|
296
312
|
|
|
@@ -427,3 +443,61 @@ async function tag(version) {
|
|
|
427
443
|
|
|
428
444
|
console.log(`Created tag v${version} and pushed branch ${branch}`);
|
|
429
445
|
}
|
|
446
|
+
|
|
447
|
+
// https://docs.nodebb.org/api/read/
|
|
448
|
+
// https://docs.nodebb.org/api/write/
|
|
449
|
+
async function notify() {
|
|
450
|
+
if (!process.env.NODEBB_API_TOKEN) return exit('NODEBB_API_TOKEN env var has to be set');
|
|
451
|
+
const apiToken = process.env.NODEBB_API_TOKEN;
|
|
452
|
+
|
|
453
|
+
const manifestFilePath = locateManifest();
|
|
454
|
+
if (!manifestFilePath) return exit('Could not locate CloudronManifest.json');
|
|
455
|
+
|
|
456
|
+
const result = manifestFormat.parseFile(manifestFilePath);
|
|
457
|
+
if (result.error) return exit(new Error(`Invalid CloudronManifest.json: ${result.error.message}`));
|
|
458
|
+
const { manifest } = result;
|
|
459
|
+
|
|
460
|
+
let postContent = null;
|
|
461
|
+
if (manifest.changelog.slice(0, 7) === 'file://') {
|
|
462
|
+
const baseDir = path.dirname(manifestFilePath);
|
|
463
|
+
let changelogPath = manifest.changelog.slice(7);
|
|
464
|
+
changelogPath = path.isAbsolute(changelogPath) ? changelogPath : path.join(baseDir, changelogPath);
|
|
465
|
+
const changelog = parseChangelog(changelogPath, manifest.version);
|
|
466
|
+
if (!changelog) return exit('Bad changelog format or missing changelog for this version');
|
|
467
|
+
postContent = `[${manifest.version}]\n${changelog}\n`;
|
|
468
|
+
} else {
|
|
469
|
+
postContent = `[${manifest.version}]\n${manifest.changelog}\n`;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (!manifest.forumUrl) return exit(new Error('CloudronManifest.json does not have a forumUrl'));
|
|
473
|
+
const categoryMatch = manifest.forumUrl.match(/category\/(.*)\//);
|
|
474
|
+
if (!categoryMatch) return exit('Unable to detect category id');
|
|
475
|
+
const categoryId = categoryMatch[1];
|
|
476
|
+
|
|
477
|
+
const categoryResponse = await superagent.get(`https://forum.cloudron.io/api/v3/categories/${categoryId}/topics`).set('Authorization', `Bearer ${apiToken}`).ok(() => true);
|
|
478
|
+
if (categoryResponse.statusCode !== 200) return exit(`Unable to get topics of category: ${requestError(categoryResponse)}`);
|
|
479
|
+
const topic = categoryResponse.body.response.topics.find(t => t.title.includes('Package Updates'));
|
|
480
|
+
if (!topic) return exit('Could not find the Package Update topic');
|
|
481
|
+
const topicId = topic.tid;
|
|
482
|
+
|
|
483
|
+
const pageCountResponse = await superagent.get(`https://forum.cloudron.io/api/topic/pagination/${topicId}`).set('Authorization', `Bearer ${apiToken}`).ok(() => true);
|
|
484
|
+
if (pageCountResponse.statusCode !== 200) return exit(`Unable to get page count of topic: ${requestError(pageCountResponse)}`);
|
|
485
|
+
const pageCount = pageCountResponse.body.pagination.pageCount;
|
|
486
|
+
|
|
487
|
+
for (let page = 1; page <= pageCount; page++) {
|
|
488
|
+
const pageResponse = await superagent.get(`https://forum.cloudron.io/api/topic/${topicId}?page=${page}`).set('Authorization', `Bearer ${apiToken}`).ok(() => true);
|
|
489
|
+
if (pageResponse.statusCode !== 200) return exit(`Unable to get topics of category: ${requestError(pageResponse)}`);
|
|
490
|
+
for (const post of pageResponse.body.posts) { // post.content is html!
|
|
491
|
+
if (post.content.includes(`[${manifest.version}]`)) return exit(`Version ${manifest.version} is already on the forum.\n${post.content}`);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// https://docs.nodebb.org/api/write/#tag/topics/paths/~1topics~1%7Btid%7D/post
|
|
496
|
+
const postData = {
|
|
497
|
+
content: postContent,
|
|
498
|
+
toPid: 0 // which post is this post a reply to
|
|
499
|
+
};
|
|
500
|
+
const postResponse = await superagent.post(`https://forum.cloudron.io/api/v3/topics/${topicId}`).set('Authorization', `Bearer ${apiToken}`).send(postData).ok(() => true);
|
|
501
|
+
if (postResponse.statusCode !== 200) return exit(`Unable to create changelog post: ${requestError(postResponse)}`);
|
|
502
|
+
console.log('Posted to forum');
|
|
503
|
+
}
|
package/src/build-actions.js
CHANGED
|
@@ -331,6 +331,7 @@ async function build(localOptions, cmd) {
|
|
|
331
331
|
config.setAppConfig(sourceDir, appConfig);
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
+
appConfig.gitCommit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim(); // when the build gets saved, save the gitCommit also
|
|
334
335
|
if (buildServiceConfig.type === 'local') {
|
|
335
336
|
await buildLocal(manifest, sourceDir, appConfig, options);
|
|
336
337
|
} else if (buildServiceConfig.type === 'remote' && buildServiceConfig.url) {
|
|
@@ -363,14 +364,21 @@ async function push(localOptions, cmd) {
|
|
|
363
364
|
const options = cmd.optsWithGlobals();
|
|
364
365
|
|
|
365
366
|
if (!options.id) return exit('buildId is required');
|
|
366
|
-
|
|
367
|
-
if (
|
|
367
|
+
let repository, tag;
|
|
368
|
+
if (options.image) {
|
|
369
|
+
[repository, tag] = options.image.split(':');
|
|
370
|
+
} else {
|
|
371
|
+
if (!options.repository) return exit('repository is required');
|
|
372
|
+
if (!options.tag) return exit('tag is required');
|
|
373
|
+
repository = options.repository;
|
|
374
|
+
tag = options.tag;
|
|
375
|
+
}
|
|
368
376
|
|
|
369
377
|
const buildServiceConfig = getBuildServiceConfig(options);
|
|
370
378
|
|
|
371
379
|
const response = await superagent.post(`${buildServiceConfig.url}/api/v1/builds/${options.id}/push`)
|
|
372
380
|
.query({ accessToken: buildServiceConfig.token })
|
|
373
|
-
.send({ dockerImageRepo:
|
|
381
|
+
.send({ dockerImageRepo: repository, dockerImageTag: tag })
|
|
374
382
|
.ok(() => true);
|
|
375
383
|
if (response.statusCode !== 201) return exit(`Failed to push: ${requestError(response)}`);
|
|
376
384
|
|