lib/plugins/aws/info/index.js/AwsInfo/gather
class AwsInfo:  gather() {
    const stackName = this.provider.getStackName(this.options.stage);
    const info = {
      service: this.serverless.service.service,
      stage: this.options.stage,
      region: this.options.region,
    };

    // Get info from CloudFormation Outputs
    return this.provider.request('CloudFormation',
      'describeStacks',
      { StackName: stackName },
      this.options.stage,
      this.options.region)
    .then((result) => {
      let outputs;

      if (result) {
        outputs = result.Stacks[0].Outputs;

        // Functions
        info.functions = [];
        outputs.filter(x => x.OutputKey.match(/LambdaFunctionArn$/))
          .forEach(x => {
            const functionInfo = {};
            functionInfo.arn = x.OutputValue;
            functionInfo.name = functionInfo.arn.substring(x.OutputValue.lastIndexOf(':') + 1);
            info.functions.push(functionInfo);
          });

        // Endpoints
        outputs.filter(x => x.OutputKey.match(/^ServiceEndpoint/))
          .forEach(x => {
            info.endpoint = x.OutputValue;
          });

        // Resources
        info.resources = [];

        // API Keys
        info.apiKeys = [];
      }

      // create a gatheredData object which can be passed around ("[call] by reference")
      const gatheredData = {
        outputs,
        info,
      };

      return BbPromise.resolve(gatheredData);
    })
    .then((gatheredData) => this.getApiKeyValues(gatheredData))
    .then((gatheredData) => BbPromise.resolve(gatheredData))
    .catch((e) => {
      let result;

      if (e.code === 'ValidationError') {
        // stack doesn't exist, provide only the general info
        const data = { info, outputs: [] };
        result = BbPromise.resolve(data);
      } else {
        // other aws sdk errors
        result = BbPromise.reject(new this.serverless.classes
          .Error(e.message));
      }

      return result;
    });
  }