Add endpoint to revert client app version
This commit is contained in:
parent
4eb6d1e624
commit
0ce553eaf2
|
@ -34,9 +34,10 @@ const {
|
||||||
const { clientLibraryPath } = require("../../utilities")
|
const { clientLibraryPath } = require("../../utilities")
|
||||||
const { getAllLocks } = require("../../utilities/redis")
|
const { getAllLocks } = require("../../utilities/redis")
|
||||||
const {
|
const {
|
||||||
uploadClientLibrary,
|
updateClientLibrary,
|
||||||
downloadLibraries,
|
backupClientLibrary,
|
||||||
} = require("../../utilities/fileSystem/newApp")
|
revertClientLibrary,
|
||||||
|
} = require("../../utilities/fileSystem/clientLibrary")
|
||||||
|
|
||||||
const URL_REGEX_SLASH = /\/|\\/g
|
const URL_REGEX_SLASH = /\/|\\/g
|
||||||
|
|
||||||
|
@ -247,7 +248,8 @@ exports.updateClient = async function (ctx) {
|
||||||
const currentVersion = application.version
|
const currentVersion = application.version
|
||||||
|
|
||||||
// Update client library and manifest
|
// Update client library and manifest
|
||||||
await uploadClientLibrary(ctx.params.appId)
|
await backupClientLibrary(ctx.params.appId)
|
||||||
|
await updateClientLibrary(ctx.params.appId)
|
||||||
|
|
||||||
// Update versions in app package
|
// Update versions in app package
|
||||||
const appPackageUpdates = {
|
const appPackageUpdates = {
|
||||||
|
@ -259,6 +261,27 @@ exports.updateClient = async function (ctx) {
|
||||||
ctx.body = data
|
ctx.body = data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.revertClient = async function (ctx) {
|
||||||
|
// Check app can be reverted
|
||||||
|
const db = new CouchDB(ctx.params.appId)
|
||||||
|
const application = await db.get(DocumentTypes.APP_METADATA)
|
||||||
|
if (!application.revertableVersion) {
|
||||||
|
ctx.throw(400, "There is no version to revert to")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update client library and manifest
|
||||||
|
await revertClientLibrary(ctx.params.appId)
|
||||||
|
|
||||||
|
// Update versions in app package
|
||||||
|
const appPackageUpdates = {
|
||||||
|
version: application.revertableVersion,
|
||||||
|
revertableVersion: null,
|
||||||
|
}
|
||||||
|
const data = await updateAppPackage(ctx, appPackageUpdates, ctx.params.appId)
|
||||||
|
ctx.status = 200
|
||||||
|
ctx.body = data
|
||||||
|
}
|
||||||
|
|
||||||
exports.delete = async function (ctx) {
|
exports.delete = async function (ctx) {
|
||||||
const db = new CouchDB(ctx.params.appId)
|
const db = new CouchDB(ctx.params.appId)
|
||||||
|
|
||||||
|
@ -290,10 +313,7 @@ const updateAppPackage = async (ctx, appPackage, appId) => {
|
||||||
delete newAppPackage.lockedBy
|
delete newAppPackage.lockedBy
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await db.put(newAppPackage)
|
return await db.put(newAppPackage)
|
||||||
console.log(response)
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const createEmptyAppPackage = async (ctx, app) => {
|
const createEmptyAppPackage = async (ctx, app) => {
|
||||||
|
|
|
@ -16,6 +16,11 @@ router
|
||||||
authorized(BUILDER),
|
authorized(BUILDER),
|
||||||
controller.updateClient
|
controller.updateClient
|
||||||
)
|
)
|
||||||
|
.post(
|
||||||
|
"/api/applications/:appId/client/revert",
|
||||||
|
authorized(BUILDER),
|
||||||
|
controller.revertClient
|
||||||
|
)
|
||||||
.delete("/api/applications/:appId", authorized(BUILDER), controller.delete)
|
.delete("/api/applications/:appId", authorized(BUILDER), controller.delete)
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
const { join } = require("path")
|
||||||
|
const { ObjectStoreBuckets } = require("../../constants")
|
||||||
|
const fs = require("fs")
|
||||||
|
const { upload, retrieveToTmp, streamUpload } = require("./utilities")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client library paths in the object store:
|
||||||
|
* Previously, the entire standard-components package was downloaded from NPM
|
||||||
|
* as a tarball and extracted to the object store, even though only the manifest
|
||||||
|
* was ever needed. Therefore we need to support old apps which may still have
|
||||||
|
* the manifest at this location for the first update.
|
||||||
|
*
|
||||||
|
* The new paths for the in-use version are:
|
||||||
|
* {appId}/manifest.json
|
||||||
|
* {appId}/budibase-client.js
|
||||||
|
*
|
||||||
|
* The paths for the backups are:
|
||||||
|
* {appId}/manifest.json.bak
|
||||||
|
* {appId}/budibase-client.js.bak
|
||||||
|
*
|
||||||
|
* We don't rely on NPM at all any more, as when updating to the latest version
|
||||||
|
* we pull both the manifest and client bundle from the server's dependencies
|
||||||
|
* in the local file system.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backs up the current client library version by copying both the manifest
|
||||||
|
* and client bundle to .bak extensions in the object store. Only the one
|
||||||
|
* previous version is stored as a backup, which can be reverted to.
|
||||||
|
* @param appId The app ID to backup
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
exports.backupClientLibrary = async appId => {
|
||||||
|
let tmpManifestPath
|
||||||
|
let tmpClientPath
|
||||||
|
|
||||||
|
// Copy existing manifest to tmp
|
||||||
|
try {
|
||||||
|
// Try to load the manifest from the new file location
|
||||||
|
tmpManifestPath = await retrieveToTmp(
|
||||||
|
ObjectStoreBuckets.APPS,
|
||||||
|
join(appId, "manifest.json")
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
// Fallback to loading it from the old location for old apps
|
||||||
|
tmpManifestPath = await retrieveToTmp(
|
||||||
|
ObjectStoreBuckets.APPS,
|
||||||
|
join(
|
||||||
|
appId,
|
||||||
|
"node_modules",
|
||||||
|
"budibase",
|
||||||
|
"standard-components",
|
||||||
|
"package",
|
||||||
|
"manifest.json"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy existing client lib to tmp
|
||||||
|
tmpClientPath = await retrieveToTmp(
|
||||||
|
ObjectStoreBuckets.APPS,
|
||||||
|
join(appId, "budibase-client.js")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Upload manifest as backup
|
||||||
|
await upload({
|
||||||
|
bucket: ObjectStoreBuckets.APPS,
|
||||||
|
filename: join(appId, "manifest.json.bak"),
|
||||||
|
path: tmpManifestPath,
|
||||||
|
type: "application/json",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Upload client library as backup
|
||||||
|
await upload({
|
||||||
|
bucket: ObjectStoreBuckets.APPS,
|
||||||
|
filename: join(appId, "budibase-client.js.bak"),
|
||||||
|
path: tmpClientPath,
|
||||||
|
type: "application/javascript",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploads the latest version of the component manifest and the client library
|
||||||
|
* to the object store, overwriting the existing version.
|
||||||
|
* @param appId The app ID to update
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
exports.updateClientLibrary = async appId => {
|
||||||
|
// Upload latest component manifest
|
||||||
|
await streamUpload(
|
||||||
|
ObjectStoreBuckets.APPS,
|
||||||
|
join(appId, "manifest.json"),
|
||||||
|
fs.createReadStream(
|
||||||
|
require.resolve("@budibase/standard-components/manifest.json")
|
||||||
|
),
|
||||||
|
{
|
||||||
|
ContentType: "application/json",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Upload latest component library
|
||||||
|
await streamUpload(
|
||||||
|
ObjectStoreBuckets.APPS,
|
||||||
|
join(appId, "budibase-client.js"),
|
||||||
|
fs.createReadStream(require.resolve("@budibase/client")),
|
||||||
|
{
|
||||||
|
ContentType: "application/javascript",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverts the version of the client library and manifest to the previously
|
||||||
|
* used version for an app.
|
||||||
|
* @param appId The app ID to revert
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
exports.revertClientLibrary = async appId => {
|
||||||
|
let tmpManifestPath
|
||||||
|
let tmpClientPath
|
||||||
|
|
||||||
|
// Copy backup manifest to tmp
|
||||||
|
tmpManifestPath = await retrieveToTmp(
|
||||||
|
ObjectStoreBuckets.APPS,
|
||||||
|
join(appId, "manifest.json.bak")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Copy backup client lib to tmp
|
||||||
|
tmpClientPath = await retrieveToTmp(
|
||||||
|
ObjectStoreBuckets.APPS,
|
||||||
|
join(appId, "budibase-client.js.bak")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Upload manifest backup
|
||||||
|
await upload({
|
||||||
|
bucket: ObjectStoreBuckets.APPS,
|
||||||
|
filename: join(appId, "manifest.json"),
|
||||||
|
path: tmpManifestPath,
|
||||||
|
type: "application/json",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Upload client library backup
|
||||||
|
await upload({
|
||||||
|
bucket: ObjectStoreBuckets.APPS,
|
||||||
|
filename: join(appId, "budibase-client.js"),
|
||||||
|
path: tmpClientPath,
|
||||||
|
type: "application/javascript",
|
||||||
|
})
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ const {
|
||||||
deleteFolder,
|
deleteFolder,
|
||||||
downloadTarball,
|
downloadTarball,
|
||||||
} = require("./utilities")
|
} = require("./utilities")
|
||||||
const { uploadClientLibrary } = require("./newApp")
|
const { updateClientLibrary } = require("./clientLibrary")
|
||||||
const download = require("download")
|
const download = require("download")
|
||||||
const env = require("../../environment")
|
const env = require("../../environment")
|
||||||
const { homedir } = require("os")
|
const { homedir } = require("os")
|
||||||
|
@ -139,12 +139,12 @@ exports.performBackup = async (appId, backupName) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Downloads required libraries and creates a new path in the object store.
|
* Uploads the latest client library to the object store.
|
||||||
* @param {string} appId The ID of the app which is being created.
|
* @param {string} appId The ID of the app which is being created.
|
||||||
* @return {Promise<void>} once promise completes app resources should be ready in object store.
|
* @return {Promise<void>} once promise completes app resources should be ready in object store.
|
||||||
*/
|
*/
|
||||||
exports.createApp = async appId => {
|
exports.createApp = async appId => {
|
||||||
await uploadClientLibrary(appId)
|
await updateClientLibrary(appId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
const { join } = require("path")
|
|
||||||
const { ObjectStoreBuckets } = require("../../constants")
|
|
||||||
const { streamUpload } = require("./utilities")
|
|
||||||
const fs = require("fs")
|
|
||||||
|
|
||||||
const BUCKET_NAME = ObjectStoreBuckets.APPS
|
|
||||||
|
|
||||||
exports.uploadClientLibrary = async appId => {
|
|
||||||
await streamUpload(
|
|
||||||
BUCKET_NAME,
|
|
||||||
join(appId, "budibase-client.js"),
|
|
||||||
fs.createReadStream(require.resolve("@budibase/client")),
|
|
||||||
{
|
|
||||||
ContentType: "application/javascript",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
await streamUpload(
|
|
||||||
BUCKET_NAME,
|
|
||||||
join(appId, "manifest.json"),
|
|
||||||
fs.createReadStream(
|
|
||||||
require.resolve("@budibase/standard-components/manifest.json")
|
|
||||||
),
|
|
||||||
{
|
|
||||||
ContentType: "application/javascript",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
Loading…
Reference in New Issue