Repository: ACloudGuru/serverless-plugin-aws-alerts (js)
Issue: prefixTemplate is ignored if nameTemplate is not specified
# This is a Bug Report

## Description

For bug reports:
* What went wrong?
I specified prefixTemplate in both the global section and definitions section and it appears to be ignored.  Alarms are still prefixed with the stack name.  If nameTemplate is specified, then the value is used.

* What did you expect should have happened?
The value of prefixTemplate changes my alarm names despite nameTemplate not being specified.

* What was the config you used?
```
custom:
  prune:
    automatic: true
    number: 5
  pythonRequirements:
    dockerizePip: non-linux
    layer:
      compatibleRuntimes:
        - python3.8
  alerts:
    prefixTemplate: my-prefix-${{self:provider.stage}}
    definitions:
      SQSErrorAlarm:
        prefixTemplate: my-prefix-${{self:provider.stage}}
         ...
```

* What stacktrace or error message from your provider did you see?
N/A

Similar or dependent issues:
* N/A

## Additional Data

* ***Serverless Framework Version***: 2.3.0
* ***Plugin Version***: 1.6.1
* ***Stack Trace***: N/A
* ***Provider Error messages***: N/A

Pull request description: Use prefixTemplate even if nameTemplate is not defined
## What did you implement:

Closes #141 

## How did you implement it:

If nameTemplate is undefined and prefixTemplate is defined, use a default format of `${prefixTemplate}-$[functionName]-$[metricName]`

## How can we verify it:

1. Add updated plugin version as a dependency to the example project: `yarn add -D Marcholio/serverless-plugin-aws-alerts#fix/prefixTemplate`
2. Run dryRun deployment of the example project `sls deploy --stage staging --noDeploy`
3. Note that configured alerts do not contain `AlarmName` property
4. Add `prefixTemplate: my-prefix-${opt:stage}` to alert configuration. Do not define nameTemplate.
5. Run dryRun deployment
6. Note that the alerts have `AlarmName` property with value matching the defined default format.
7. Define different prefix for one function, eg.
```yaml
functions:
  foo:
    handler: foo.handler
    alarms: # merged with function alarms
      - customAlarm
      - name: fooAlarm
        .....
        prefixTemplate: other-prefix
```
8. Run dry run deployment
9. Verify that foo function has `AlarmName` property with "other-prefix" as a prefix.

## Todos:

- [X] Write tests
- [X] Write documentation
- [X] Fix linting errors
- [X] Provide verification config/commands/resources



Patch:
diff --git a/src/index.js b/src/index.js
index 6491d13..83d6e0d 100644
--- a/src/index.js
+++ b/src/index.js
@@ -235,7 +235,7 @@ class AlertsPlugin {
       };
     } else {
       throw new Error(
-        `Missing type for alarm ${alarm.name} on function ${functionName}, must be one of 'static' or 'anomalyDetection'`
+        `Missing type for alarm ${definition.name} on function ${functionName}, must be one of 'static' or 'anomalyDetection'`
       );
     }
 
@@ -249,7 +249,18 @@ class AlertsPlugin {
         functionName,
         stackName,
       });
+    } else if (definition.prefixTemplate) {
+      alarm.Properties.AlarmName = this.naming.getAlarmName({
+        template: '$[functionName]-$[metricName]',
+        prefixTemplate: definition.prefixTemplate,
+        functionLogicalId: functionRef,
+        metricName: definition.name || definition.metric,
+        metricId,
+        functionName,
+        stackName,
+      });
     }
+
     return alarm;
   }
 


Test patch:
diff --git a/src/index.test.js b/src/index.test.js
index 259bf93..b1433fb 100644
--- a/src/index.test.js
+++ b/src/index.test.js
@@ -1437,7 +1437,7 @@ describe('#index', () => {
       });
     });
 
-    it('should add AlarmName property when nameTemplate is defined', () => {
+    it('should use nameTemplate when it is defined', () => {
       const alertTopics = {
         ok: 'ok-topic',
         alarm: 'alarm-topic',
@@ -1495,6 +1495,64 @@ describe('#index', () => {
       });
     });
 
+    it('should use prefixTemplate when it is defined, even if nameTemplate is not defined', () => {
+      const alertTopics = {
+        ok: 'ok-topic',
+        alarm: 'alarm-topic',
+        insufficientData: 'insufficientData-topic',
+      };
+
+      const definition = {
+        prefixTemplate: 'test-prefix',
+        description: 'An error alarm',
+        type: 'static',
+        name: 'test-alarm',
+        namespace: 'AWS/Lambda',
+        metric: 'Errors',
+        threshold: 1,
+        period: 300,
+        evaluationPeriods: 1,
+        comparisonOperator: 'GreaterThanThreshold',
+        treatMissingData: 'breaching',
+      };
+
+      const functionName = 'func-name';
+      const functionRef = 'func-ref';
+
+      const cf = plugin.getAlarmCloudFormation(
+        alertTopics,
+        definition,
+        functionName,
+        functionRef
+      );
+
+      expect(cf).toEqual({
+        Type: 'AWS::CloudWatch::Alarm',
+        Properties: {
+          AlarmName: `test-prefix-${functionName}-${definition.name}`,
+          AlarmDescription: definition.description,
+          Namespace: definition.namespace,
+          MetricName: definition.metric,
+          Threshold: definition.threshold,
+          Period: definition.period,
+          EvaluationPeriods: definition.evaluationPeriods,
+          ComparisonOperator: definition.comparisonOperator,
+          OKActions: ['ok-topic'],
+          AlarmActions: ['alarm-topic'],
+          InsufficientDataActions: ['insufficientData-topic'],
+          Dimensions: [
+            {
+              Name: 'FunctionName',
+              Value: {
+                Ref: functionRef,
+              },
+            },
+          ],
+          TreatMissingData: 'breaching',
+        },
+      });
+    });
+
     it('should generate an AnomalyDetection alarm when type is anomalyDetection', () => {
       const alertTopics = {
         ok: 'ok-topic',