serverless/lib/plugins/aws/deploy-list.js
Austen 9c787096a1
Fix Spinner Experience & Improve Messaging (#12564)
* fix: remove spinner, make dev mode notice infrequent

* fix: make dev mode notice less frequent

* fix: improve dev mode closure warning

* fix: improve disconnection notice for dev mode functions

* feat: improve dev mode messaging and list endpoints and functions

* fix: do not display dev mode notice for non-node functions
2024-05-30 13:38:54 -07:00

173 lines
5.0 KiB
JavaScript

import utils from '@serverlessinc/sf-core/src/utils.js'
import validate from './lib/validate.js'
import findAndGroupDeployments from './utils/find-and-group-deployments.js'
import setBucketName from './lib/set-bucket-name.js'
import ServerlessError from '../../serverless-error.js'
const { log, progress, writeText } = utils
class AwsDeployList {
constructor(serverless, options, pluginUtils) {
this.serverless = serverless
this.options = options || {}
this.provider = this.serverless.getProvider('aws')
this.logger = pluginUtils.log
this.progress = pluginUtils.progress
Object.assign(this, validate, setBucketName)
this.hooks = {
'before:deploy:list:log': () => this.validate(),
'before:deploy:list:functions:log': () => this.validate(),
'deploy:list:log': async () => {
this.progress.notice('Fetching deployments')
await this.setBucketName()
await this.listDeployments()
},
'deploy:list:functions:log': async () => this.listFunctions(),
}
}
async listDeployments() {
const service = this.serverless.service.service
const stage = this.provider.getStage()
const prefix = this.provider.getDeploymentPrefix()
let response
try {
response = await this.provider.request('S3', 'listObjectsV2', {
Bucket: this.bucketName,
Prefix: `${prefix}/${service}/${stage}`,
})
} catch (err) {
if (err.code === 'AWS_S3_LIST_OBJECTS_V2_ACCESS_DENIED') {
throw new ServerlessError(
'Could not list objects in the deployment bucket. Make sure you have sufficient permissions to access it.',
err.code,
)
}
throw err
}
const directoryRegex = new RegExp('(.+)-(.+-.+-.+)')
const deployments = findAndGroupDeployments(
response,
prefix,
service,
stage,
)
if (deployments.length === 0) {
log.aside(
"No deployments found, if that's unexpected ensure that stage and region are correct",
)
return
}
this.progress.remove()
deployments.forEach((deployment) => {
const match = deployment[0].directory.match(directoryRegex)
const date = new Date(Date.parse(match[2]))
this.logger.notice(
`${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(
2,
0,
)}-${String(date.getUTCDate()).padStart(2, 0)} ${String(
date.getUTCHours(),
).padStart(2, 0)}:${String(date.getUTCMinutes()).padStart(
2,
0,
)}:${String(date.getUTCSeconds()).padStart(2, 0)} UTC`,
)
this.logger.aside(`Timestamp: ${match[1]}`)
this.logger.aside('Files:')
deployment.forEach((entry) => {
this.logger.aside(` - ${entry.file}`)
})
// If this is not the last item in the array, show blank line
if (deployment !== deployments[deployments.length - 1])
this.logger.blankLine()
})
}
// list all functions and their versions
async listFunctions() {
const funcs = await this.getFunctions()
const funcsVersions = await this.getFunctionVersions(funcs)
this.displayFunctions(funcsVersions)
}
async getFunctions() {
const funcs = this.serverless.service.getAllFunctionsNames()
const result = await Promise.all(
funcs.map((funcName) => {
const params = {
FunctionName: funcName,
}
return this.provider.request('Lambda', 'getFunction', params)
}),
)
return result.map((item) => item.Configuration)
}
async getFunctionPaginatedVersions(params, totalVersions) {
const response = await this.provider.request(
'Lambda',
'listVersionsByFunction',
params,
)
const Versions = (totalVersions || []).concat(response.Versions)
if (response.NextMarker) {
return this.getFunctionPaginatedVersions(
{ ...params, Marker: response.NextMarker },
Versions,
)
}
return { Versions }
}
async getFunctionVersions(funcs) {
return Promise.all(
funcs.map((func) => {
const params = {
FunctionName: func.FunctionName,
}
return this.getFunctionPaginatedVersions(params)
}),
)
}
displayFunctions(funcs) {
this.progress.remove()
funcs.forEach((func) => {
let name = func.Versions[0].FunctionName
name = name.replace(`${this.serverless.service.service}-`, '')
name = name.replace(`${this.provider.getStage()}-`, '')
this.logger.notice(name)
const versionsLength = func.Versions.length
const versions = func.Versions.map(
(funcEntry) => funcEntry.Version,
).slice(Math.max(0, func.Versions.length - 5))
if (versionsLength < 6)
this.logger.aside(` All Versions: ${versions.join(', ')}`)
else this.logger.aside(` Latest Versions: ${versions.join(', ')}`)
// If this is not the last item in the array, show blank line
if (func !== funcs[funcs.length - 1]) this.logger.blankLine()
})
}
}
export default AwsDeployList