cloudron 5.11.5 → 5.11.6

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
@@ -32,7 +32,6 @@ program.option('--server <server>', 'Cloudron domain')
32
32
 
33
33
  // these are separate binaries since global options are not applicable
34
34
  program.command('appstore', 'Cloudron appstore commands');
35
- program.command('repo', 'Cloudron repo commands');
36
35
  program.command('build', 'Cloudron build commands');
37
36
 
38
37
  const backupCommand = program.command('backup')
@@ -22,16 +22,15 @@ program.command('info')
22
22
  .option('--appstore-id <appid@version>', 'Appstore id and version')
23
23
  .action(appstoreActions.info);
24
24
 
25
- program.command('published')
26
- .description('List published apps from this account')
27
- .option('-i --image', 'Display docker image')
28
- .action(appstoreActions.listPublishedApps);
29
-
30
25
  program.command('approve')
31
26
  .description('Approve a submitted app version')
32
27
  .option('--appstore-id <appid@version>', 'Appstore id and version')
33
28
  .action(appstoreActions.approve);
34
29
 
30
+ program.command('publish <version>')
31
+ .description('Tag the repo and publish')
32
+ .action(appstoreActions.publish);
33
+
35
34
  program.command('revoke')
36
35
  .description('Revoke a published app version')
37
36
  .option('--appstore-id <appid@version>', 'Appstore id and version')
@@ -41,12 +40,6 @@ program.command('submit')
41
40
  .description('Submit app to the store for review')
42
41
  .action(appstoreActions.submit);
43
42
 
44
- program.command('unpublish')
45
- .description('Delete app or app version from the store')
46
- .option('--appstore-id <id@[version]>', 'Unpublish app')
47
- .option('-f, --force', 'Do not ask anything')
48
- .action(appstoreActions.unpublish);
49
-
50
43
  program.command('upload')
51
44
  .description('Upload app to the store for testing')
52
45
  .option('-i, --image <image>', 'Docker image')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudron",
3
- "version": "5.11.5",
3
+ "version": "5.11.6",
4
4
  "license": "MIT",
5
5
  "description": "Cloudron Commandline Tool",
6
6
  "main": "main.js",
@@ -4,12 +4,14 @@
4
4
 
5
5
  const assert = require('assert'),
6
6
  config = require('./config.js'),
7
+ execSync = require('child_process').execSync,
7
8
  fs = require('fs'),
8
9
  { exit, locateManifest } = require('./helper.js'),
9
10
  manifestFormat = require('cloudron-manifestformat'),
10
11
  path = require('path'),
11
12
  readlineSync = require('readline-sync'),
12
13
  safe = require('safetydance'),
14
+ semver = require('semver'),
13
15
  superagent = require('superagent'),
14
16
  Table = require('easy-table');
15
17
 
@@ -22,8 +24,8 @@ exports = module.exports = {
22
24
  upload,
23
25
  revoke,
24
26
  approve,
25
- unpublish,
26
- listPublishedApps
27
+
28
+ publish
27
29
  };
28
30
 
29
31
  const NO_MANIFEST_FOUND_ERROR_STRING = 'No CloudronManifest.json found';
@@ -267,22 +269,6 @@ async function updateVersion(manifest, baseDir) {
267
269
  if (response.statusCode !== 204) throw new Error(`Failed to publish version: ${requestError(response)}`);
268
270
  }
269
271
 
270
- async function delVersion(manifest, force) {
271
- assert.strictEqual(typeof manifest, 'object');
272
- assert.strictEqual(typeof force, 'boolean');
273
-
274
- if (!force) {
275
- console.log(`This will delete the version ${manifest.version} of app ${manifest.id} from the appstore!`);
276
- const reallyDelete = readlineSync.question('Really do this? [y/N]: ', {});
277
- if (reallyDelete.toUpperCase() !== 'Y') exit();
278
- }
279
-
280
- const response = await createRequest('DEL', `/api/v1/developers/apps/${manifest.id}/versions/${manifest.version}`);
281
- if (response.statusCode !== 204) return exit(`Failed to unpublish version: ${requestError(response)}`);
282
-
283
- console.log('version unpublished.');
284
- }
285
-
286
272
  async function revokeVersion(appstoreId, version) {
287
273
  assert.strictEqual(typeof appstoreId, 'string');
288
274
  assert.strictEqual(typeof version, 'string');
@@ -313,22 +299,6 @@ async function approveVersion(appstoreId, version) {
313
299
  console.log('');
314
300
  }
315
301
 
316
- async function delApp(appId, force) {
317
- assert.strictEqual(typeof appId, 'string');
318
- assert.strictEqual(typeof force, 'boolean');
319
-
320
- if (!force) {
321
- console.log('This will delete app %s from the appstore!', appId);
322
- const reallyDelete = readlineSync.question('Really do this? [y/N]: ', {});
323
- if (reallyDelete.toUpperCase() !== 'Y') return exit();
324
- }
325
-
326
- const response = await createRequest('DEL', `/api/v1/developers/apps/${appId}`);
327
- if (response.statusCode !== 204) exit(`Failed to unpublish app : ${requestError(response)}`);
328
-
329
- console.log('App unpublished.');
330
- }
331
-
332
302
  async function submitAppForReview(manifest) {
333
303
  assert.strictEqual(typeof manifest, 'object');
334
304
 
@@ -380,30 +350,17 @@ async function upload(options) {
380
350
 
381
351
  function submit() {
382
352
  // try to find the manifest of this project
383
- var manifestFilePath = locateManifest();
353
+ const manifestFilePath = locateManifest();
384
354
  if (!manifestFilePath) return exit(NO_MANIFEST_FOUND_ERROR_STRING);
385
355
 
386
- var result = manifestFormat.parseFile(manifestFilePath);
356
+ const result = manifestFormat.parseFile(manifestFilePath);
387
357
  if (result.error) return exit(result.error.message);
388
358
 
389
- var manifest = result.manifest;
359
+ const manifest = result.manifest;
390
360
 
391
361
  submitAppForReview(manifest, exit);
392
362
  }
393
363
 
394
- async function unpublish(options) {
395
- const [id, version] = await getAppstoreId(options.appstoreId);
396
-
397
- if (!version) {
398
- console.log(`Unpublishing ${options.appstoreId}`);
399
- await delApp(options.app, !!options.force);
400
- return;
401
- }
402
-
403
- console.log(`Unpublishing ${id}@${version}`);
404
- await delVersion(id, !!options.force);
405
- }
406
-
407
364
  async function revoke(options) {
408
365
  const [id, version] = await getAppstoreId(options.appstoreId);
409
366
  if (!version) return exit('--appstore-id must be of the format id@version');
@@ -422,24 +379,84 @@ async function approve(options) {
422
379
  await approveVersion(id, version);
423
380
  }
424
381
 
425
- // TODO currently no pagination, only needed once we have users with more than 100 apps
426
- async function listPublishedApps(options) {
427
- const response = await createRequest('GET', '/api/v1/developers/apps?per_page=100');
428
- if (response.statusCode !== 200) return exit(`Failed to get list of published apps: ${requestError(response)}`);
429
- if (response.body.apps.length === 0) return console.log('No apps published.');
382
+ async function tagRepository(version) {
383
+ const basename = `${path.basename(process.cwd())}`;
384
+ if (!basename.endsWith('-app')) return exit('Does not look like a app repo. Has to end with -app');
430
385
 
431
- const t = new Table();
386
+ if (!semver.valid(version)) return exit(`${version} is not a valid semver`);
432
387
 
433
- response.body.apps.forEach(function (app) {
434
- t.cell('Id', app.id);
435
- t.cell('Title', app.manifest.title);
436
- t.cell('Latest Version', app.manifest.version);
437
- t.cell('Publish State', app.publishState);
438
- t.cell('Creation Date', new Date(app.creationDate));
439
- if (options.image) t.cell('Image', app.manifest.dockerImage);
440
- t.newRow();
441
- });
388
+ const latestTag = safe.child_process.execSync('git describe --tags --abbrev=0', { encoding: 'utf8' });
389
+ if (safe.error) return exit(`Failed to get last release tag: ${safe.error.message}`);
442
390
 
443
- console.log();
444
- console.log(t.toString());
391
+ const manifestFilePath = locateManifest();
392
+ if (!manifestFilePath) return exit('Could not locate CloudronManifest.json');
393
+
394
+ const result = manifestFormat.parseFile(manifestFilePath);
395
+ if (result.error) throw new Error(`Invalid CloudronManifest.json: ${result.error.message}`);
396
+ const { manifest } = result;
397
+
398
+ const latestVersion = latestTag.match(/v(.*)/)[1];
399
+
400
+ if (semver.lte(version, latestVersion)) return exit(`${version} is less than or equal to last repo tag ${latestVersion}`);
401
+ if (semver.inc(latestVersion, 'major') !== version
402
+ && semver.inc(latestVersion, 'minor') !== version
403
+ && semver.inc(latestVersion, 'patch') !== version) {
404
+ return exit(`${version} is not the next major/minor/patch of last published version ${latestVersion}`);
405
+ }
406
+
407
+ const latestRenovateCommit = safe.child_process.execSync('git log -n 1 --committer=renovatebot@cloudron.io --pretty="format:%h,%aI,%s"', { encoding: 'utf8' });
408
+ if (!latestRenovateCommit) return exit('Could not find a commit from renovate bot');
409
+
410
+ const [ , , commitMessage ] = latestRenovateCommit.split(',');
411
+ const repoDir = path.dirname(manifestFilePath);
412
+ const upstreamVersion = commitMessage.match(/update dependency .* to (.*)/)[1];
413
+
414
+ console.log(`Enter the changelog for ${upstreamVersion}: (press ctrl+D to finish)`);
415
+ const rawChangelog = fs.readFileSync(0, 'utf-8');
416
+ const mdChangelog = rawChangelog.split('\n').map(line => {
417
+ line = line.trim();
418
+ line = line.replace(/[\u{0080}-\u{FFFF}]/gu, ''); // only ascii
419
+ line = line.replace(/^\* /, ''); // replace any "* " in the front
420
+ return line ? `* ${line}` : '';
421
+ }).join('\n');
422
+ const newChangelog = `\n[${version}]\n* Update ${manifest.title} to ${upstreamVersion}\n${mdChangelog}\n`;
423
+ const changelogFile = `${repoDir}/${manifest.changelog.replace('file://', '')}`; // sometimes CHANGELOG, sometimes CHANGELOG.md
424
+ fs.appendFileSync(changelogFile, newChangelog);
425
+
426
+ manifest.version = version;
427
+ manifest.upstreamVersion = upstreamVersion;
428
+ fs.writeFileSync('CloudronManifest.json', JSON.stringify(manifest, null, 2));
429
+
430
+ // git branch --show-current does not work in CI :/
431
+ const mainOrMaster = safe.child_process.execSync('git branch -r --list origin/master origin/main', { encoding: 'utf8' });
432
+ if (safe.error) return exit('Could not determine branch name');
433
+ const branch = mainOrMaster.includes('master') ? 'master' : 'main';
434
+
435
+ execSync(`git commit -a -m 'Version ${version}'`, { encoding: 'utf8' });
436
+ execSync(`git tag v${version} -a -m 'Version ${version}'`, { encoding: 'utf8' });
437
+ console.log(`git push --atomic origin ${branch} v${version}`);
438
+ execSync(`git push --atomic origin HEAD:${branch} v${version}`, { encoding: 'utf8' }); // push this tag only. in CI, we might have a git cache
439
+ if (safe.error) return exit(`Failed to push tag v${version} and branch ${branch}: ${safe.error.message}`, { encoding: 'utf8' });
440
+
441
+ console.log(`Created tag v${version} and pushed branch ${branch}`);
442
+ }
443
+
444
+ async function publish(version, options) {
445
+ await tagRepository(version);
446
+
447
+ const manifestFilePath = locateManifest();
448
+ if (!manifestFilePath) return exit('Could not locate CloudronManifest.json');
449
+
450
+ const latestRenovateCommit = safe.child_process.execSync('git log -n 1 --committer=renovatebot@cloudron.io --pretty="format:%h,%aI,%s"', { encoding: 'utf8' });
451
+ if (!latestRenovateCommit) return exit('Could not find a commit from renovate bot');
452
+
453
+ const [ abbrevHash, commitDate ] = latestRenovateCommit.split(',');
454
+ const cleanDate = commitDate.replace(/T.*/, '').replace(/[-]/g, '');
455
+ const repoDir = path.dirname(manifestFilePath);
456
+ const repoName = path.basename(repoDir).replace('-app', '');
457
+ const dockerImage = options.image || `cloudron/${repoName}:${cleanDate}-${abbrevHash}`;
458
+
459
+ await upload({ image: dockerImage, force: false });
460
+ await submit();
461
+ await approve();
445
462
  }
package/bin/cloudron-repo DELETED
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- 'use strict';
4
-
5
- const { program } = require('commander'),
6
- repoActions = require('../src/repo-actions.js');
7
-
8
- program.version(require('../package.json').version);
9
-
10
- program.command('tag <version>')
11
- .description('Creates a new release with given tag')
12
- .action(repoActions.tag);
13
-
14
- program.command('publish')
15
- .description('Publish to appstore')
16
- .action(repoActions.publish);
17
-
18
- program.parse(process.argv);
@@ -1,102 +0,0 @@
1
- /* jshint node:true */
2
-
3
- 'use strict';
4
-
5
- const { exit, locateManifest } = require('./helper.js'),
6
- execSync = require('child_process').execSync,
7
- fs = require('fs'),
8
- manifestFormat = require('cloudron-manifestformat'),
9
- path = require('path'),
10
- safe = require('safetydance'),
11
- semver = require('semver');
12
-
13
- exports = module.exports = {
14
- tag,
15
- publish
16
- };
17
-
18
- async function tag(version, options) {
19
- const basename = `${path.basename(process.cwd())}`;
20
- if (!basename.endsWith('-app')) return exit('Does not look like a app repo. Has to end with -app');
21
-
22
- if (!semver.valid(version)) return exit(`${version} is not a valid semver`);
23
-
24
- const latestTag = safe.child_process.execSync('git describe --tags --abbrev=0', { encoding: 'utf8' });
25
- if (safe.error) return exit(`Failed to get last release tag: ${safe.error.message}`);
26
-
27
- const manifestFilePath = locateManifest();
28
- if (!manifestFilePath) return exit('Could not locate CloudronManifest.json');
29
-
30
- const latestVersion = latestTag.match(/v(.*)/)[1];
31
-
32
- if (semver.lte(version, latestVersion)) return exit(`${version} is less than or equal to last repo tag ${latestVersion}`);
33
- if (semver.inc(latestVersion, 'major') !== version
34
- && semver.inc(latestVersion, 'minor') !== version
35
- && semver.inc(latestVersion, 'patch') !== version) {
36
- return exit(`${version} is not the next major/minor/patch of last published version ${latestVersion}`);
37
- }
38
-
39
- const latestRenovateCommit = safe.child_process.execSync('git log -n 1 --committer=renovatebot@cloudron.io --pretty="format:%h,%aI,%s"', { encoding: 'utf8' });
40
- if (!latestRenovateCommit) return exit('Could not find a commit from renovate bot');
41
-
42
- const [ abbrevHash, commitDate, commitMessage ] = latestRenovateCommit.split(',');
43
- const cleanDate = commitDate.replace(/T.*/, '').replace(/[-]/g, '');
44
- const repoDir = path.dirname(manifestFilePath);
45
- const repoName = path.basename(repoDir).replace('-app', '');
46
- const dockerImage = options.image || `cloudron/${repoName}:${cleanDate}-${abbrevHash}`;
47
- const upstreamVersion = commitMessage.match(/update dependency .* to (.*)/)[1];
48
-
49
- const result = manifestFormat.parseFile(manifestFilePath);
50
- if (result.error) throw new Error(`Invalid CloudronManifest.json: ${result.error.message}`);
51
- const { manifest } = result;
52
-
53
- console.log(`Enter the changelog for ${upstreamVersion}: (press ctrl+D to finish)`);
54
- const rawChangelog = fs.readFileSync(0, 'utf-8');
55
- const mdChangelog = rawChangelog.split('\n').map(line => {
56
- line = line.trim();
57
- line = line.replace(/[\u{0080}-\u{FFFF}]/gu, ''); // only ascii
58
- line = line.replace(/^\* /, ''); // replace any "* " in the front
59
- return line ? `* ${line}` : '';
60
- }).join('\n');
61
- const newChangelog = `\n[${version}]\n* Update ${manifest.title} to ${upstreamVersion}\n${mdChangelog}\n`;
62
- const changelogFile = `${repoDir}/${manifest.changelog.replace('file://', '')}`; // sometimes CHANGELOG, sometimes CHANGELOG.md
63
- fs.appendFileSync(changelogFile, newChangelog);
64
-
65
- manifest.version = version;
66
- manifest.upstreamVersion = upstreamVersion;
67
- fs.writeFileSync('CloudronManifest.json', JSON.stringify(manifest, null, 2));
68
-
69
- // git branch --show-current does not work in CI :/
70
- const mainOrMaster = safe.child_process.execSync('git branch -r --list origin/master origin/main', { encoding: 'utf8' });
71
- if (safe.error) return exit('Could not determine branch name');
72
- const branch = mainOrMaster.includes('master') ? 'master' : 'main';
73
-
74
- execSync(`git commit -a -m 'Version ${version}'`, { encoding: 'utf8' });
75
- execSync(`git tag v${version} -a -m 'Version ${version}'`, { encoding: 'utf8' });
76
- console.log(`git push --atomic origin ${branch} v${version}`);
77
- execSync(`git push --atomic origin HEAD:${branch} v${version}`, { encoding: 'utf8' }); // push this tag only. in CI, we might have a git cache
78
- if (safe.error) return exit(`Failed to push tag v${version} and branch ${branch}: ${safe.error.message}`, { encoding: 'utf8' });
79
-
80
- console.log(`Created tag v${version} and pushed branch ${branch}`);
81
- }
82
-
83
- async function publish(options) {
84
- const manifestFilePath = locateManifest();
85
- if (!manifestFilePath) return exit('Could not locate CloudronManifest.json');
86
-
87
- const latestRenovateCommit = safe.child_process.execSync('git log -n 1 --committer=renovatebot@cloudron.io --pretty="format:%h,%aI,%s"', { encoding: 'utf8' });
88
- if (!latestRenovateCommit) return exit('Could not find a commit from renovate bot');
89
-
90
- const [ abbrevHash, commitDate ] = latestRenovateCommit.split(',');
91
- const cleanDate = commitDate.replace(/T.*/, '').replace(/[-]/g, '');
92
- const repoDir = path.dirname(manifestFilePath);
93
- const repoName = path.basename(repoDir).replace('-app', '');
94
- const dockerImage = options.image || `cloudron/${repoName}:${cleanDate}-${abbrevHash}`;
95
-
96
- safe.child_process.execSync(`cloudron appstore upload --image ${dockerImage}`);
97
- if (safe.error) return exit(`Failed to publish image to appstore: ${safe.error.message}`);
98
- execSync(`cloudron appstore submit`);
99
- execSync(`cloudron appstore approve`);
100
-
101
- console.log('Published to appstore');
102
- }