All files plugin.ts

29.41% Statements 15/51
14.29% Branches 2/14
28% Functions 7/25
34.88% Lines 15/43
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143  1x 1x 1x 1x     2x 2x 2x     2x     1x     1x           4x     2x     2x     2x                                                                                                   1x                                                                                                                      
import * as  assert from 'assert'
import * as  util from 'util'
 
import StackOutputFile from './file'
 
class StackOutputPlugin {
  public hooks: {}
  private output: OutputConfig
 
  constructor (private serverless: Serverless, private options: Serverless.Options) {
    this.hooks = {
      'after:deploy:deploy': this.process.bind(this)
    }
 
    this.output = this.serverless.service.custom.output
  }
 
  get file () {
    return this.getConfig('file')
  }

  get handler () {
    return this.getConfig('handler')
  }
 
  get stackName () {
    return this.serverless.service.getServiceName() + '-' + this.serverless.getProvider('aws').getStage()
  }
 
  private hasConfig (key: string) {
    return !!this.output && !!this.output[key]
  }
 
  private hasHandler () {
    return this.hasConfig('handler')
  }

  private hasFile () {
    return this.hasConfig('file')
  }

  private getConfig (key: string) {
    return this.serverless.config.servicePath + '/' + this.output[key]
  }

  private callHandler (data: {}) {
    const splits = this.handler.split('.')
    const func = splits.pop() || ''
 
    return new Promise((resolve) => {
      require(splits.join('.'))[func](data, this.serverless)

      resolve()
    })
  }

  private saveFile (data: {}) {
    const f = new StackOutputFile(this.file)

    return new Promise((resolve) => {
      f.save(data)

      resolve()
    })
  }

  private fetch (): Promise<StackDescriptionList> {
    return this.serverless.getProvider('aws').request(
      'CloudFormation',
      'describeStacks',
      {
        StackName: this.stackName
      },
      this.serverless.getProvider('aws').getStage(),
      this.serverless.getProvider('aws').getRegion()
    )
  }
 
  private beautify (data: {Stacks: Array<{ Outputs: Array<{}> }>}) {
    const stack = data.Stacks.pop() || { Outputs: [] }
    const output = stack.Outputs || []
 
    return output.reduce(
      (obj: {}, item: StackOutputPair) => Object.assign(obj, {[item.OutputKey]: item.OutputValue}),
      {}
    )
  }
 
  private handle (data: {}) {
    const promises = []
 
    if (this.hasHandler()) {
      promises.push(
        this.callHandler(data).then(
          () => this.serverless.cli.log(
            util.format('Stack Output processed with handler: %s', this.output.handler)
          )
        )
      )
    }
 
    if (this.hasFile()) {
      promises.push(
        this.saveFile(data).then(
          () => this.serverless.cli.log(
            util.format('Stack Output saved to file: %s', this.output.file)
          )
        )
      )
    }
 
    return Promise.all(promises)
  }
 
  private validate () {
    assert(this.serverless, 'Invalid serverless configuration')
    assert(this.serverless.service, 'Invalid serverless configuration')
    assert(this.serverless.service.provider, 'Invalid serverless configuration')
    assert(this.serverless.service.provider.name, 'Invalid serverless configuration')
    assert(this.serverless.service.provider.name === 'aws', 'Only supported for AWS provider')
 
    assert(this.options && !this.options.noDeploy, 'Skipping deployment with --noDeploy flag')
  }
 
  private process () {
    console.log('running stack-output-plugin')
 
    return Promise.resolve().then(
      () => this.validate()
    ).then(
      () => this.fetch()
    ).then(
      (res: StackDescriptionList) => this.beautify(res)
    ).then(
      (res) => this.handle(res)
    ).catch(
      (err) => this.serverless.cli.log(util.format('Cannot process Stack Output: %s!', err.message))
    )
  }
}
 
module.exports = StackOutputPlugin