cloudron 8.1.0 → 8.1.2

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 CHANGED
@@ -27,7 +27,15 @@ program.option('--server <server>', 'Cloudron domain')
27
27
  .option('--no-wait', 'Do not wait for the operation to finish');
28
28
 
29
29
  const appstoreCommand = program.command('appstore').description('Commands for publishing to the Appstore')
30
- .requiredOption('--appstore-token <token>', 'AppStore token');
30
+ .option('--appstore-token <token>', 'AppStore token');
31
+
32
+ appstoreCommand.command('login')
33
+ .description('Login to the appstore')
34
+ .action(appstoreActions.login);
35
+
36
+ appstoreCommand.command('logout')
37
+ .description('Logout from the appstore')
38
+ .action(appstoreActions.logout);
31
39
 
32
40
  appstoreCommand.command('info')
33
41
  .description('List info of published app')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudron",
3
- "version": "8.1.0",
3
+ "version": "8.1.2",
4
4
  "license": "MIT",
5
5
  "description": "Cloudron Commandline Tool",
6
6
  "type": "module",
@@ -23,7 +23,7 @@
23
23
  "commander": "^14.0.3",
24
24
  "debug": "^4.4.3",
25
25
  "easy-table": "^1.2.0",
26
- "ejs": "^5.0.1",
26
+ "ejs": "^5.0.2",
27
27
  "eventsource": "^4.1.0",
28
28
  "micromatch": "^4.0.8",
29
29
  "open": "^11.0.0",
@@ -35,8 +35,8 @@
35
35
  },
36
36
  "devDependencies": {
37
37
  "@eslint/js": "^10.0.1",
38
- "eslint": "^10.0.3",
39
- "globals": "^17.4.0",
38
+ "eslint": "^10.2.0",
39
+ "globals": "^17.5.0",
40
40
  "mocha": "^11.7.5"
41
41
  }
42
42
  }
@@ -2,10 +2,9 @@ import assert from 'assert';
2
2
  import * as config from './config.js';
3
3
  import { execSync } from 'child_process';
4
4
  import fs from 'fs';
5
- import { exit, locateManifest, parseChangelog } from './helper.js';
5
+ import { exit, locateManifest, parseChangelog, performOidcLogin } from './helper.js';
6
6
  import manifestFormat from '@cloudron/manifest-format';
7
7
  import path from 'path';
8
- import * as readline from './readline.js';
9
8
  import safe from '@cloudron/safetydance';
10
9
  import superagent from '@cloudron/superagent';
11
10
  import Table from 'easy-table';
@@ -15,7 +14,7 @@ const NO_MANIFEST_FOUND_ERROR_STRING = 'No CloudronManifest.json found';
15
14
  function requestError(response) {
16
15
  if (response.status === 401) return 'Invalid token.';
17
16
 
18
- return `${response.status} message: ${response.body?.message || response.text || JSON.stringify(response.body)}`; // body is sometimes just a string like in 401
17
+ return `${response.status} message: ${response.body?.message || JSON.stringify(response.body)}`;
19
18
  }
20
19
 
21
20
  function createRequest(method, apiPath, options) {
@@ -393,38 +392,67 @@ async function notify() {
393
392
 
394
393
  if (!manifest.forumUrl) return exit(new Error('CloudronManifest.json does not have a forumUrl'));
395
394
  const categoryMatch = manifest.forumUrl.match(/category\/(.*)\//);
396
- if (!categoryMatch) return exit('Unable to detect category id');
395
+ if (!categoryMatch) return exit(`Unable to detect category id from forumUrl: ${manifest.forumUrl}`);
397
396
  const categoryId = categoryMatch[1];
398
397
 
398
+ console.log(`[notify] appId: ${manifest.id} version: ${manifest.version} forumUrl: ${manifest.forumUrl} categoryId: ${categoryId}`);
399
+
399
400
  const categoryResponse = await superagent.get(`https://forum.cloudron.io/api/v3/categories/${categoryId}/topics`).set('Authorization', `Bearer ${apiToken}`).ok(() => true);
400
- if (categoryResponse.status !== 200) return exit(`Unable to get topics of category: ${requestError(categoryResponse)}`);
401
- const topic = categoryResponse.body.response.topics.find(t => t.title.toLowerCase().includes('Package Updates'.toLowerCase()));
401
+ if (categoryResponse.status !== 200) return exit(`Unable to get topics of category (status ${categoryResponse.status}): ${requestError(categoryResponse)}`);
402
+
403
+ const allTopics = categoryResponse.body.response.topics;
404
+ console.log(`[notify] Got ${allTopics.length} topics in category. Titles: ${allTopics.map(t => t.title).join(', ')}`);
405
+
406
+ const topic = allTopics.find(t => t.title.toLowerCase().includes('package updates'));
402
407
  if (!topic) return exit('Could not find the Package Update topic');
403
408
  const topicId = topic.tid;
409
+ console.log(`[notify] Found "Package Updates" topic tid: ${topicId}`);
404
410
 
405
411
  const pageCountResponse = await superagent.get(`https://forum.cloudron.io/api/topic/pagination/${topicId}`).set('Authorization', `Bearer ${apiToken}`).ok(() => true);
406
- if (pageCountResponse.status !== 200) return exit(`Unable to get page count of topic: ${requestError(pageCountResponse)}`);
412
+ if (pageCountResponse.status !== 200) return exit(`Unable to get page count of topic (status ${pageCountResponse.status}): ${requestError(pageCountResponse)}`);
407
413
  const pageCount = pageCountResponse.body.pagination.pageCount;
414
+ console.log(`[notify] Topic has ${pageCount} pages to scan for duplicates`);
408
415
 
409
416
  for (let page = 1; page <= pageCount; page++) {
410
417
  const pageResponse = await superagent.get(`https://forum.cloudron.io/api/topic/${topicId}?page=${page}`).set('Authorization', `Bearer ${apiToken}`).ok(() => true);
411
- if (pageResponse.status !== 200) return exit(`Unable to get topics of category: ${requestError(pageResponse)}`);
412
- for (const post of pageResponse.body.posts) { // post.content is html!
418
+ if (pageResponse.status !== 200) return exit(`Unable to get posts of topic page ${page} (status ${pageResponse.status}): ${requestError(pageResponse)}`);
419
+ console.log(`[notify] Page ${page}/${pageCount}: ${pageResponse.body.posts.length} posts`);
420
+ for (const post of pageResponse.body.posts) {
413
421
  if (post.content.includes(`[${manifest.version}]`)) return exit(`Version ${manifest.version} is already on the forum.\n${post.content}`);
414
422
  }
415
423
  }
416
424
 
425
+ console.log(`[notify] No duplicate found, posting version ${manifest.version}`);
426
+
417
427
  // https://docs.nodebb.org/api/write/#tag/topics/paths/~1topics~1%7Btid%7D/post
418
428
  const postData = {
419
429
  content: postContent,
420
430
  toPid: 0 // which post is this post a reply to
421
431
  };
422
432
  const postResponse = await superagent.post(`https://forum.cloudron.io/api/v3/topics/${topicId}`).set('Authorization', `Bearer ${apiToken}`).send(postData).ok(() => true);
423
- if (postResponse.status !== 200) return exit(`Unable to create changelog post: ${requestError(postResponse)}`);
433
+ if (postResponse.status !== 200) return exit(`Unable to create changelog post (status ${postResponse.status}): ${requestError(postResponse)}`);
424
434
  console.log('Posted to forum');
425
435
  }
426
436
 
437
+ async function login() {
438
+ const origin = config.appStoreOrigin();
439
+ const consoleFqdn = origin.replace('https://', '').replace('api.', 'console.') + '/openid';
440
+
441
+ const token = await performOidcLogin(consoleFqdn);
442
+ if (!token) process.exit(1);
443
+
444
+ config.setAppStoreToken(token);
445
+ console.log('Login successful.');
446
+ }
447
+
448
+ function logout() {
449
+ config.setAppStoreToken(null);
450
+ console.log('Logged out.');
451
+ }
452
+
427
453
  export default {
454
+ login,
455
+ logout,
428
456
  info,
429
457
  listVersions,
430
458
  submit,