diff --git a/bin/assistant-server.js b/bin/assistant-server.js old mode 100755 new mode 100644 diff --git a/package.json b/package.json index 09f071e..e667297 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/envision-cli", - "version": "0.0.45", + "version": "0.0.46", "description": "envision command tools", "main": "dist/app.mjs", "type": "module", diff --git a/src/command/deploy.ts b/src/command/deploy.ts index 2d4d06b..fe1a4d7 100644 --- a/src/command/deploy.ts +++ b/src/command/deploy.ts @@ -9,6 +9,7 @@ import inquirer from 'inquirer'; import { packLib, unpackLib } from './publish.ts'; import chalk from 'chalk'; import { installDeps } from '@/uitls/npm.ts'; +import { MD5 } from 'crypto-js'; /** * 获取package.json 中的 basename, version, user, appKey * @returns @@ -43,9 +44,14 @@ const command = new Command('deploy') .option('-o, --org ', 'org') .option('-u, --update', 'load current app. set current version in product。 redis 缓存更新') .option('-s, --showBackend', 'show backend url, 部署的后端应用,显示执行的cli命令') + .option('-c, --noCheck', '是否受app manager控制的模块。默认检测') + .option('-d, --dot', '是否上传隐藏文件') + .option('--dir, --directory ', '上传的默认路径') .action(async (filePath, options) => { try { let { version, key, yes, update, org, showBackend } = options; + const noCheck = !options.noCheck; + const dot = !!options.dot; // 获取当前目录,是否存在package.json, 如果有,从package.json 获取 version 和basename const pkgInfo = getPackageJson(); if (!version && pkgInfo?.version) { @@ -54,7 +60,7 @@ const command = new Command('deploy') if (!key && pkgInfo?.appKey) { key = pkgInfo?.appKey || ''; } - console.log('start deploy') + console.log('start deploy'); if (!version || !key) { const answers = await inquirer.prompt([ { @@ -82,7 +88,7 @@ const command = new Command('deploy') if (stat.isDirectory()) { isDirectory = true; const gPath = path.join(directory, '**/*'); - const files = await glob(gPath, { cwd: pwd, ignore: ['node_modules/**/*'], onlyFiles: true }); + const files = await glob(gPath, { cwd: pwd, ignore: ['node_modules/**/*'], onlyFiles: true, dot }); _relativeFiles = files.map((file) => path.relative(directory, file)); } else if (stat.isFile()) { const filename = path.basename(directory); @@ -104,13 +110,13 @@ const command = new Command('deploy') } } const uploadDirectory = isDirectory ? directory : path.dirname(directory); - const res = await uploadFiles(_relativeFiles, uploadDirectory, { key, version, username: org }); + const res = await uploadFiles(_relativeFiles, uploadDirectory, { key, version, username: org, noCheckAppFiles: !noCheck, directory: options.directory }); if (res?.code === 200) { console.log('File uploaded successfully!'); - res.data?.data?.files?.map?.((d) => { - console.log('uploaded file', d?.name, d?.path); + res.data?.upload?.map?.((d) => { + console.log(chalk.green('uploaded file', d?.name, d?.path)); }); - const { id, data, ...rest } = res.data || {}; + const { id, data, ...rest } = res.data?.app || {}; if (id && !update) { console.log(chalk.green('id: '), id); if (!org) { @@ -121,7 +127,7 @@ const command = new Command('deploy') } else if (id && update) { deployLoadFn(id); } else { - console.log('rest error', JSON.stringify(rest, null, 2)); + // console.log('rest', JSON.stringify(res.data, null, 2)); } if (id && showBackend) { console.log('\n'); @@ -142,34 +148,92 @@ const command = new Command('deploy') console.error('error', error); } }); - -const uploadFiles = async ( - files: string[], - directory: string, - { key, version, username }: { key: string; version: string; username: string }, -): Promise => { +export const getHash = (file: string) => { + const content = fs.readFileSync(file, 'utf-8'); + return MD5(content).toString(); +}; +type UploadFileOptions = { + key: string; + version: string; + username?: string; + noCheckAppFiles?: boolean; + directory?: string; +}; +const uploadFiles = async (files: string[], directory: string, opts: UploadFileOptions): Promise => { + const { key, version, username } = opts || {}; const config = await getConfig(); const form = new FormData(); + const data: Record = { files: [] }; for (const file of files) { const filePath = path.join(directory, file); - form.append('file', fs.createReadStream(filePath), { - filename: file, - filepath: file, - }); + const hash = getHash(filePath); + data.files.push({ path: file, hash: hash }); } + data.appKey = key; + data.version = version; form.append('appKey', key); form.append('version', version); if (username) { form.append('username', username); + data.username = username; } + if (opts?.directory) { + form.append('directory', opts.directory); + data.directory = opts.directory; + } + const token = await storage.getItem('token'); + const checkUrl = new URL('/api/s1/resources/upload/check', getBaseURL()); + const res = await query + .adapter({ url: checkUrl.toString(), method: 'POST', body: data, headers: { Authorization: 'Bearer ' + token, contentType: 'application/json' } }) + .then((res) => { + try { + if (typeof res === 'string') { + return JSON.parse(res); + } else { + return res; + } + } catch (error) { + return typeof res === 'string' ? {} : res; + } + }); + const checkData: { path: string; isUpload: boolean }[] = res.data; + if (res.code !== 200) { + console.error('check failed', res); + return res; + } + let needUpload = false; + for (const file of files) { + const filePath = path.join(directory, file); + const check = checkData.find((d) => d.path === file); + if (check?.isUpload) { + console.log('文件已经上传过了', file); + continue; + } + form.append('file', fs.createReadStream(filePath), { + filename: file, + filepath: file, + }); + needUpload = true; + } + if (!needUpload) { + console.log('所有文件都上传过了,不需要上传文件'); + return { + code: 200, + }; + } + return new Promise(async (resolve) => { const _baseURL = getBaseURL(); - const url = new URL(_baseURL); + const url = new URL('/api/s1/resources/upload', _baseURL); + const searchParams = url.searchParams; + if (opts.noCheckAppFiles) { + searchParams.append('noCheckAppFiles', 'true'); + } console.log('upload url', url.hostname, url.protocol, url.port); - const token = await storage.getItem('token'); + const pathname = url.href.toString().replace(_baseURL.toString(), ''); form.submit( { - path: '/api/app/upload', + path: pathname, host: url.hostname, protocol: url.protocol as any, port: url.port, diff --git a/test/code/node/.npmrc b/test/code/node/.npmrc new file mode 100644 index 0000000..0a2c6cd --- /dev/null +++ b/test/code/node/.npmrc @@ -0,0 +1,3 @@ +//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN} +//registry.npmjs.org/:_authToken=${NPM_TOKEN} +ignore-workspace-root-check=true \ No newline at end of file diff --git a/test/index.html b/test/index.html deleted file mode 100644 index 30d74d2..0000000 --- a/test/index.html +++ /dev/null @@ -1 +0,0 @@ -test \ No newline at end of file diff --git a/test/test-cli.html b/test/test-cli.html new file mode 100644 index 0000000..a70dda4 --- /dev/null +++ b/test/test-cli.html @@ -0,0 +1 @@ +test-cli deploy2 \ No newline at end of file