mirror of
https://github.com/sasjs/server.git
synced 2025-12-10 11:24:35 +00:00
feat(deploy): new route added for deploy with build.json
This commit is contained in:
14
api/package-lock.json
generated
14
api/package-lock.json
generated
@@ -9,7 +9,7 @@
|
||||
"version": "0.0.2",
|
||||
"dependencies": {
|
||||
"@sasjs/core": "4.9.0",
|
||||
"@sasjs/utils": "2.36.2",
|
||||
"@sasjs/utils": "2.42.1",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"cors": "^2.8.5",
|
||||
@@ -1384,9 +1384,9 @@
|
||||
"integrity": "sha512-zc1Ey0ylHt/eRZAfK0mVG3EqNyq//wLxbiguiK0R6FhVqwYFEkprs3IiLGZ5M9ttKs2rHRIjOe/ckklHm+6HNQ=="
|
||||
},
|
||||
"node_modules/@sasjs/utils": {
|
||||
"version": "2.36.2",
|
||||
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.36.2.tgz",
|
||||
"integrity": "sha512-r0O9vkNIK5+2peBiGbcKc3Ei62eAMDt+1SQl17U9Vv26LYqezxQBwIYYMUjnkZE8Q7XlTI/FUS+SIHTCZMr4Jg==",
|
||||
"version": "2.42.1",
|
||||
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.42.1.tgz",
|
||||
"integrity": "sha512-DzHNYjeoj2eUkwV7Sa4eHCKRoTrYaQ6eyv6c1U5qOYXwVdZpMoYA3HFsHj55UcMOn2U3CXI5nrR7PZlUmVwVbQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@types/fs-extra": "9.0.13",
|
||||
@@ -11132,9 +11132,9 @@
|
||||
"integrity": "sha512-zc1Ey0ylHt/eRZAfK0mVG3EqNyq//wLxbiguiK0R6FhVqwYFEkprs3IiLGZ5M9ttKs2rHRIjOe/ckklHm+6HNQ=="
|
||||
},
|
||||
"@sasjs/utils": {
|
||||
"version": "2.36.2",
|
||||
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.36.2.tgz",
|
||||
"integrity": "sha512-r0O9vkNIK5+2peBiGbcKc3Ei62eAMDt+1SQl17U9Vv26LYqezxQBwIYYMUjnkZE8Q7XlTI/FUS+SIHTCZMr4Jg==",
|
||||
"version": "2.42.1",
|
||||
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.42.1.tgz",
|
||||
"integrity": "sha512-DzHNYjeoj2eUkwV7Sa4eHCKRoTrYaQ6eyv6c1U5qOYXwVdZpMoYA3HFsHj55UcMOn2U3CXI5nrR7PZlUmVwVbQ==",
|
||||
"requires": {
|
||||
"@types/fs-extra": "9.0.13",
|
||||
"@types/prompts": "2.0.13",
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
"author": "4GL Ltd",
|
||||
"dependencies": {
|
||||
"@sasjs/core": "4.9.0",
|
||||
"@sasjs/utils": "2.36.2",
|
||||
"@sasjs/utils": "2.42.1",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"cors": "^2.8.5",
|
||||
|
||||
@@ -606,6 +606,56 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DeployPayload'
|
||||
/SASjsApi/drive/deploy/upload:
|
||||
post:
|
||||
operationId: DeployUpload
|
||||
responses:
|
||||
'200':
|
||||
description: Ok
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DeployResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {status: success, message: 'Files deployed successfully to @sasjs/server.'}
|
||||
'400':
|
||||
description: 'Invalid Format'
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DeployResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {status: failure, message: 'Provided not supported data format.'}
|
||||
'500':
|
||||
description: 'Execution Error'
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DeployResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {status: failure, message: 'Deployment failed!'}
|
||||
summary: 'Creates/updates files within SASjs Drive using uploaded JSON file.'
|
||||
tags:
|
||||
- Drive
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
parameters: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
file:
|
||||
type: string
|
||||
format: binary
|
||||
required:
|
||||
- file
|
||||
/SASjsApi/drive/file:
|
||||
get:
|
||||
operationId: GetFile
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import path from 'path'
|
||||
import {
|
||||
CompileTree,
|
||||
createFile,
|
||||
loadDependenciesFile,
|
||||
readFile,
|
||||
@@ -18,7 +19,8 @@ const compiledSystemInit = async (systemInit: string) =>
|
||||
macroFolders: [],
|
||||
buildSourceFolder: '',
|
||||
binaryFolders: [],
|
||||
macroCorePath
|
||||
macroCorePath,
|
||||
compileTree: new CompileTree('') // dummy compileTree
|
||||
}))
|
||||
|
||||
const createSysInitFile = async () => {
|
||||
|
||||
@@ -14,7 +14,8 @@ import {
|
||||
Patch,
|
||||
UploadedFile,
|
||||
FormField,
|
||||
Delete
|
||||
Delete,
|
||||
Hidden
|
||||
} from 'tsoa'
|
||||
import {
|
||||
fileExists,
|
||||
@@ -22,14 +23,15 @@ import {
|
||||
createFolder,
|
||||
deleteFile as deleteFileOnSystem,
|
||||
folderExists,
|
||||
listFilesAndSubFoldersInFolder,
|
||||
listFilesInFolder,
|
||||
listSubFoldersInFolder,
|
||||
isFolder
|
||||
isFolder,
|
||||
FileTree,
|
||||
isFileTree
|
||||
} from '@sasjs/utils'
|
||||
import { createFileTree, ExecutionController, getTreeExample } from './internal'
|
||||
|
||||
import { FileTree, isFileTree, TreeNode } from '../types'
|
||||
import { TreeNode } from '../types'
|
||||
import { getTmpFilesFolderPath } from '../utils'
|
||||
|
||||
interface DeployPayload {
|
||||
@@ -93,6 +95,21 @@ export class DriveController {
|
||||
return deploy(body)
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Creates/updates files within SASjs Drive using uploaded JSON file.
|
||||
*
|
||||
*/
|
||||
@Example<DeployResponse>(successDeployResponse)
|
||||
@Response<DeployResponse>(400, 'Invalid Format', invalidDeployFormatResponse)
|
||||
@Response<DeployResponse>(500, 'Execution Error', execDeployErrorResponse)
|
||||
@Post('/deploy/upload')
|
||||
public async deployUpload(
|
||||
@UploadedFile() file: Express.Multer.File, // passing here for API docs
|
||||
@Query() @Hidden() body?: DeployPayload // Hidden decorator has be optional
|
||||
): Promise<DeployResponse> {
|
||||
return deploy(body!)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @summary Get file from SASjs Drive
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import path from 'path'
|
||||
import { getTmpFilesFolderPath } from '../../utils/file'
|
||||
import {
|
||||
MemberType,
|
||||
createFolder,
|
||||
createFile,
|
||||
asyncForEach,
|
||||
FolderMember,
|
||||
ServiceMember,
|
||||
FileTree,
|
||||
FileMember
|
||||
} from '../../types'
|
||||
import { getTmpFilesFolderPath } from '../../utils/file'
|
||||
import { createFolder, createFile, asyncForEach } from '@sasjs/utils'
|
||||
FileMember,
|
||||
MemberType,
|
||||
FileTree
|
||||
} from '@sasjs/utils'
|
||||
|
||||
// REFACTOR: export FileTreeCpntroller
|
||||
export const createFileTree = async (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import express from 'express'
|
||||
import { deleteFile } from '@sasjs/utils'
|
||||
import { deleteFile, readFile } from '@sasjs/utils'
|
||||
|
||||
import { publishAppStream } from '../appStream'
|
||||
|
||||
@@ -43,6 +43,50 @@ driveRouter.post('/deploy', async (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
driveRouter.post(
|
||||
'/deploy/upload',
|
||||
(...arg) => multerSingle('file', arg),
|
||||
async (req, res) => {
|
||||
if (!req.file) return res.status(400).send('"file" is not present.')
|
||||
|
||||
const fileContent = await readFile(req.file.path)
|
||||
|
||||
let jsonContent
|
||||
try {
|
||||
jsonContent = JSON.parse(fileContent)
|
||||
} catch (err) {
|
||||
return res.status(400).send('File containing invalid JSON content.')
|
||||
}
|
||||
|
||||
const { error, value: body } = deployValidation(jsonContent)
|
||||
if (error) return res.status(400).send(error.details[0].message)
|
||||
|
||||
try {
|
||||
const response = await controller.deployUpload(req.file, body)
|
||||
|
||||
if (body.streamWebFolder) {
|
||||
const { streamServiceName } = await publishAppStream(
|
||||
body.appLoc,
|
||||
body.streamWebFolder,
|
||||
body.streamServiceName,
|
||||
body.streamLogo
|
||||
)
|
||||
response.streamServiceName = streamServiceName
|
||||
}
|
||||
|
||||
res.send(response)
|
||||
} catch (err: any) {
|
||||
const statusCode = err.code
|
||||
|
||||
delete err.code
|
||||
|
||||
res.status(statusCode).send(err)
|
||||
} finally {
|
||||
await deleteFile(req.file.path)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
driveRouter.get('/file', async (req, res) => {
|
||||
const { error: errQ, value: query } = fileParamValidation(req.query)
|
||||
|
||||
|
||||
@@ -12,7 +12,9 @@ import {
|
||||
generateTimestamp,
|
||||
copy,
|
||||
createFolder,
|
||||
createFile
|
||||
createFile,
|
||||
ServiceMember,
|
||||
FolderMember
|
||||
} from '@sasjs/utils'
|
||||
import * as fileUtilModules from '../../../utils/file'
|
||||
|
||||
@@ -28,7 +30,6 @@ jest
|
||||
import appPromise from '../../../app'
|
||||
import { UserController } from '../../../controllers/'
|
||||
import { getTreeExample } from '../../../controllers/internal'
|
||||
import { FolderMember, ServiceMember } from '../../../types'
|
||||
import { generateAccessToken, saveTokensInDB } from '../../../utils/'
|
||||
const { getTmpFilesFolderPath } = fileUtilModules
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
export enum MemberType {
|
||||
service = 'service',
|
||||
file = 'file',
|
||||
folder = 'folder'
|
||||
}
|
||||
|
||||
export interface ServiceMember {
|
||||
name: string
|
||||
type: MemberType.service
|
||||
code: string
|
||||
}
|
||||
|
||||
export interface FileMember {
|
||||
name: string
|
||||
type: MemberType.file
|
||||
code: string
|
||||
}
|
||||
|
||||
export interface FolderMember {
|
||||
name: string
|
||||
type: MemberType.folder
|
||||
members: (FolderMember | ServiceMember | FileMember)[]
|
||||
}
|
||||
export interface FileTree {
|
||||
members: (FolderMember | ServiceMember | FileMember)[]
|
||||
}
|
||||
|
||||
export const isFileTree = (arg: any): arg is FileTree =>
|
||||
arg &&
|
||||
arg.members &&
|
||||
Array.isArray(arg.members) &&
|
||||
arg.members.filter(
|
||||
(member: ServiceMember | FileMember | FolderMember) =>
|
||||
!isServiceMember(member, '-') &&
|
||||
!isFileMember(member, '-') &&
|
||||
!isFolderMember(member, '-')
|
||||
).length === 0
|
||||
|
||||
const isServiceMember = (arg: any, pre: string): arg is ServiceMember =>
|
||||
arg &&
|
||||
typeof arg.name === 'string' &&
|
||||
arg.type === MemberType.service &&
|
||||
typeof arg.code === 'string'
|
||||
|
||||
const isFileMember = (arg: any, pre: string): arg is ServiceMember =>
|
||||
arg &&
|
||||
typeof arg.name === 'string' &&
|
||||
arg.type === MemberType.file &&
|
||||
typeof arg.code === 'string'
|
||||
|
||||
const isFolderMember = (arg: any, pre: string): arg is FolderMember =>
|
||||
arg &&
|
||||
typeof arg.name === 'string' &&
|
||||
arg.type === MemberType.folder &&
|
||||
arg.members &&
|
||||
Array.isArray(arg.members) &&
|
||||
arg.members.filter(
|
||||
(member: FolderMember | ServiceMember) =>
|
||||
!isServiceMember(member, pre + '-') &&
|
||||
!isFileMember(member, pre + '-') &&
|
||||
!isFolderMember(member, pre + '-')
|
||||
).length === 0
|
||||
@@ -1,7 +1,6 @@
|
||||
// TODO: uppercase types
|
||||
export * from './AppStreamConfig'
|
||||
export * from './Execution'
|
||||
export * from './FileTree'
|
||||
export * from './InfoJWT'
|
||||
export * from './PreProgramVars'
|
||||
export * from './Request'
|
||||
|
||||
Reference in New Issue
Block a user