cloudron 8.1.2 → 8.2.1
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/CHANGELOG.md +31 -0
- package/bin/cloudron +4 -0
- package/package.json +1 -1
- package/src/actions.js +5 -0
- package/src/versions-actions.js +81 -48
package/CHANGELOG.md
CHANGED
|
@@ -94,3 +94,34 @@
|
|
|
94
94
|
* Add `cloudron sync push` and `cloudron sync pull` subcommands
|
|
95
95
|
* Merge all binaries into single `cloudron` command
|
|
96
96
|
|
|
97
|
+
[7.1.1]
|
|
98
|
+
* Prettier login success page
|
|
99
|
+
* oidc: explicitly listen on ipv4 which is always available
|
|
100
|
+
|
|
101
|
+
[7.1.2]
|
|
102
|
+
* versions: implement revoke --version
|
|
103
|
+
* Make the login page slightly more like the dashboard style and add dark mode
|
|
104
|
+
|
|
105
|
+
[8.0.0]
|
|
106
|
+
* Implement device authorization grant flow
|
|
107
|
+
|
|
108
|
+
[8.0.1]
|
|
109
|
+
* device codes only needs to be confirmed not entered
|
|
110
|
+
* Add fallback in case the overloaded cloudron build --help is called
|
|
111
|
+
|
|
112
|
+
[8.0.2]
|
|
113
|
+
* install/update: -f and --build-arg
|
|
114
|
+
* wait even in debug mode, but just not for healthy
|
|
115
|
+
* add cloudron init --template <template>
|
|
116
|
+
* Fix cloudron pull as newer nodejs versions do not have resume() on stdout anymore
|
|
117
|
+
|
|
118
|
+
[8.1.0]
|
|
119
|
+
* Continue cloudron build even if run outside a git repository
|
|
120
|
+
* Remove old legacy appstore login/logout
|
|
121
|
+
|
|
122
|
+
[8.1.1]
|
|
123
|
+
* token is not required. verify-manifest does not need it
|
|
124
|
+
|
|
125
|
+
[8.1.2]
|
|
126
|
+
* add appstore login/logout and also forum post logs
|
|
127
|
+
|
package/bin/cloudron
CHANGED
|
@@ -437,4 +437,8 @@ versionsCommand.command('update')
|
|
|
437
437
|
.option('--state <state>', 'Publish state (published or testing)')
|
|
438
438
|
.action(versionsActions.addOrUpdate);
|
|
439
439
|
|
|
440
|
+
versionsCommand.command('verify')
|
|
441
|
+
.description('Verify if versions file is valid for publishing')
|
|
442
|
+
.action(versionsActions.verify);
|
|
443
|
+
|
|
440
444
|
program.parse(process.argv);
|
package/package.json
CHANGED
package/src/actions.js
CHANGED
|
@@ -102,6 +102,11 @@ async function stopActiveTask(app, options) {
|
|
|
102
102
|
const request = createRequest('POST', `/api/v1/tasks/${app.taskId}/stop`, options);
|
|
103
103
|
const response = await request.send({});
|
|
104
104
|
if (response.status !== 204) throw `Failed to stop active task: ${requestError(response)}`;
|
|
105
|
+
|
|
106
|
+
if (!options.wait) return;
|
|
107
|
+
|
|
108
|
+
const result = await waitForTask(app.taskId, options);
|
|
109
|
+
if (result.error) throw new Error(`Stop active task failed: ${result.error.message}`);
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
function saveCwdAppId(appId, manifestFilePath) {
|
package/src/versions-actions.js
CHANGED
|
@@ -31,51 +31,6 @@ async function writeVersions(versionsFilePath, versionsRoot) {
|
|
|
31
31
|
if (error) return exit(`Unable to write to ${path.relative(process.cwd(), versionsFilePath)}: ${error.message}`);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
async function init(/*localOptions, cmd*/) {
|
|
35
|
-
const manifestFilePath = locateManifest();
|
|
36
|
-
if (!manifestFilePath) return exit(`${NO_MANIFEST_FOUND_ERROR_STRING}. You must run this command in the package dir.`);
|
|
37
|
-
|
|
38
|
-
const baseDir = path.dirname(manifestFilePath);
|
|
39
|
-
const versionsFilePath = `${baseDir}/CloudronVersions.json`;
|
|
40
|
-
|
|
41
|
-
if (fs.existsSync(versionsFilePath)) return exit(`${path.relative(process.cwd(), versionsFilePath)} already exists.`);
|
|
42
|
-
|
|
43
|
-
await writeVersions(versionsFilePath, { stable: true, versions: {} });
|
|
44
|
-
console.log(`Created ${path.relative(process.cwd(), versionsFilePath)}.`);
|
|
45
|
-
|
|
46
|
-
const result = manifestFormat.parseFile(manifestFilePath);
|
|
47
|
-
if (!result.error) {
|
|
48
|
-
ensurePublishFields(result.manifest, manifestFilePath);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
console.log('\nUse "cloudron versions add" to add a version.');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async function resolveManifest(manifest, baseDir) {
|
|
55
|
-
if (manifest.description.slice(0, 7) === 'file://') {
|
|
56
|
-
let descriptionFilePath = manifest.description.slice(7);
|
|
57
|
-
descriptionFilePath = path.isAbsolute(descriptionFilePath) ? descriptionFilePath : path.join(baseDir, descriptionFilePath);
|
|
58
|
-
manifest.description = safe.fs.readFileSync(descriptionFilePath, 'utf8');
|
|
59
|
-
if (!manifest.description && safe.error) throw(new Error('Could not read/parse description ' + safe.error.message));
|
|
60
|
-
if (!manifest.description) throw new Error('Description cannot be empty');
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (manifest.postInstallMessage && manifest.postInstallMessage.slice(0, 7) === 'file://') {
|
|
64
|
-
let postInstallFilePath = manifest.postInstallMessage.slice(7);
|
|
65
|
-
postInstallFilePath = path.isAbsolute(postInstallFilePath) ? postInstallFilePath : path.join(baseDir, postInstallFilePath);
|
|
66
|
-
manifest.postInstallMessage = safe.fs.readFileSync(postInstallFilePath, 'utf8');
|
|
67
|
-
if (!manifest.postInstallMessage && safe.error) throw(new Error('Could not read/parse postInstall ' + safe.error.message));
|
|
68
|
-
if (!manifest.postInstallMessage) throw new Error('PostInstall file specified but it is empty');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (manifest.changelog.slice(0, 7) === 'file://') {
|
|
72
|
-
let changelogPath = manifest.changelog.slice(7);
|
|
73
|
-
changelogPath = path.isAbsolute(changelogPath) ? changelogPath : path.join(baseDir, changelogPath);
|
|
74
|
-
manifest.changelog = parseChangelog(changelogPath, manifest.version);
|
|
75
|
-
if (!manifest.changelog) throw new Error('Bad changelog format or missing changelog for this version');
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
34
|
function createStubFile(filePath, content) {
|
|
80
35
|
if (fs.existsSync(filePath)) return false;
|
|
81
36
|
fs.writeFileSync(filePath, content, 'utf8');
|
|
@@ -162,6 +117,55 @@ function ensurePublishFields(manifest, manifestFilePath) {
|
|
|
162
117
|
console.log(' tags, mediaLinks, DESCRIPTION.md, CHANGELOG, POSTINSTALL.md');
|
|
163
118
|
}
|
|
164
119
|
|
|
120
|
+
async function init(/*localOptions, cmd*/) {
|
|
121
|
+
const manifestFilePath = locateManifest();
|
|
122
|
+
if (!manifestFilePath) return exit(`${NO_MANIFEST_FOUND_ERROR_STRING}. You must run this command in the package dir.`);
|
|
123
|
+
|
|
124
|
+
const baseDir = path.dirname(manifestFilePath);
|
|
125
|
+
const versionsFilePath = `${baseDir}/CloudronVersions.json`;
|
|
126
|
+
|
|
127
|
+
if (fs.existsSync(versionsFilePath)) return exit(`${path.relative(process.cwd(), versionsFilePath)} already exists.`);
|
|
128
|
+
|
|
129
|
+
await writeVersions(versionsFilePath, { stable: true, versions: {} });
|
|
130
|
+
console.log(`Created ${path.relative(process.cwd(), versionsFilePath)}.`);
|
|
131
|
+
|
|
132
|
+
const result = manifestFormat.parseFile(manifestFilePath);
|
|
133
|
+
if (!result.error) {
|
|
134
|
+
ensurePublishFields(result.manifest, manifestFilePath);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
console.log('\nUse "cloudron versions add" to add a version.');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function resolveManifest(manifest, baseDir) {
|
|
141
|
+
const resolved = structuredClone(manifest);
|
|
142
|
+
|
|
143
|
+
if (resolved.description.slice(0, 7) === 'file://') {
|
|
144
|
+
let descriptionFilePath = resolved.description.slice(7);
|
|
145
|
+
descriptionFilePath = path.isAbsolute(descriptionFilePath) ? descriptionFilePath : path.join(baseDir, descriptionFilePath);
|
|
146
|
+
resolved.description = safe.fs.readFileSync(descriptionFilePath, 'utf8');
|
|
147
|
+
if (!resolved.description && safe.error) throw(new Error('Could not read/parse description ' + safe.error.message));
|
|
148
|
+
if (!resolved.description) throw new Error('Description cannot be empty');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (resolved.postInstallMessage && resolved.postInstallMessage.slice(0, 7) === 'file://') {
|
|
152
|
+
let postInstallFilePath = resolved.postInstallMessage.slice(7);
|
|
153
|
+
postInstallFilePath = path.isAbsolute(postInstallFilePath) ? postInstallFilePath : path.join(baseDir, postInstallFilePath);
|
|
154
|
+
resolved.postInstallMessage = safe.fs.readFileSync(postInstallFilePath, 'utf8');
|
|
155
|
+
if (!resolved.postInstallMessage && safe.error) throw(new Error('Could not read/parse postInstall ' + safe.error.message));
|
|
156
|
+
if (!resolved.postInstallMessage) throw new Error('PostInstall file specified but it is empty');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (resolved.changelog.slice(0, 7) === 'file://') {
|
|
160
|
+
let changelogPath = resolved.changelog.slice(7);
|
|
161
|
+
changelogPath = path.isAbsolute(changelogPath) ? changelogPath : path.join(baseDir, changelogPath);
|
|
162
|
+
resolved.changelog = parseChangelog(changelogPath, resolved.version);
|
|
163
|
+
if (!resolved.changelog) throw new Error('Bad changelog format or missing changelog for this version');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return resolved;
|
|
167
|
+
}
|
|
168
|
+
|
|
165
169
|
async function addOrUpdate(localOptions, cmd) {
|
|
166
170
|
const isUpdate = cmd.parent.args[0] === 'update';
|
|
167
171
|
const versionsFilePath = await locateVersions();
|
|
@@ -194,7 +198,7 @@ async function addOrUpdate(localOptions, cmd) {
|
|
|
194
198
|
const versionsRoot = await readVersions(versionsFilePath);
|
|
195
199
|
const versions = versionsRoot.versions;
|
|
196
200
|
|
|
197
|
-
await resolveManifest(manifest, path.dirname(manifestFilePath));
|
|
201
|
+
const resolved = await resolveManifest(manifest, path.dirname(manifestFilePath));
|
|
198
202
|
|
|
199
203
|
if (options.state && options.state !== PUBLISH_STATE_PUBLISHED && options.state !== PUBLISH_STATE_TESTING) {
|
|
200
204
|
return exit(`Invalid state "${options.state}". Must be "published" or "testing".`);
|
|
@@ -204,13 +208,13 @@ async function addOrUpdate(localOptions, cmd) {
|
|
|
204
208
|
const targetVersion = options.version || manifest.version;
|
|
205
209
|
if (!(targetVersion in versions)) exit(`${targetVersion} does not exist in ${path.relative(process.cwd(), versionsFilePath)}.`);
|
|
206
210
|
|
|
207
|
-
versions[targetVersion].manifest =
|
|
211
|
+
versions[targetVersion].manifest = resolved;
|
|
208
212
|
versions[targetVersion].ts = (new Date()).toUTCString();
|
|
209
213
|
if (options.state) versions[targetVersion].publishState = options.state;
|
|
210
214
|
} else {
|
|
211
215
|
if (manifest.version in versions) exit(`${manifest.version} already exists in ${path.relative(process.cwd(), versionsFilePath)}.`);
|
|
212
216
|
versions[manifest.version] = {
|
|
213
|
-
manifest,
|
|
217
|
+
manifest: resolved,
|
|
214
218
|
creationDate: (new Date()).toUTCString(),
|
|
215
219
|
ts: (new Date()).toUTCString(),
|
|
216
220
|
publishState: options.state || PUBLISH_STATE_PUBLISHED
|
|
@@ -278,9 +282,38 @@ async function revoke(localOptions, cmd) {
|
|
|
278
282
|
console.log(`Marked ${targetVersion} as revoked in ${path.relative(process.cwd(), versionsFilePath)}`);
|
|
279
283
|
}
|
|
280
284
|
|
|
285
|
+
async function verify(/* localOptions, cmd */) {
|
|
286
|
+
const versionsFilePath = await locateVersions();
|
|
287
|
+
if (!versionsFilePath) return exit(NO_VERSIONS_FOUND_ERROR_STRING);
|
|
288
|
+
|
|
289
|
+
const versionsRoot = await readVersions(versionsFilePath);
|
|
290
|
+
const versions = versionsRoot.versions;
|
|
291
|
+
|
|
292
|
+
const sortedVersions = Object.keys(versions).sort(manifestFormat.packageVersionCompare);
|
|
293
|
+
if (sortedVersions.length === 0) return exit('No versions found in versions file');
|
|
294
|
+
|
|
295
|
+
for (const version of sortedVersions) {
|
|
296
|
+
const manifest = versions[version].manifest;
|
|
297
|
+
|
|
298
|
+
if (!manifest.dockerImage) return exit(`Version ${version}: missing dockerImage`);
|
|
299
|
+
|
|
300
|
+
const error = manifestFormat.checkVersionsRequirements(manifest);
|
|
301
|
+
if (error) return exit(`Version ${version}: ${error}`);
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
await resolveManifest(manifest, path.dirname(versionsFilePath));
|
|
305
|
+
} catch (e) {
|
|
306
|
+
return exit(`Version ${version}: ${e.message}`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
console.log(`${path.relative(process.cwd(), versionsFilePath)} is valid (${sortedVersions.length} version(s))`);
|
|
311
|
+
}
|
|
312
|
+
|
|
281
313
|
export default {
|
|
282
314
|
init,
|
|
283
315
|
addOrUpdate,
|
|
284
316
|
list,
|
|
285
317
|
revoke,
|
|
318
|
+
verify,
|
|
286
319
|
};
|