Repository: serverless/serverless-azure-functions
Pull request #480 (2020-06-29 17:57:01)

fix: Check for valid index before setting name property
This commit fixes a bug when using the timer trigger where it tries to set the name of the binding. The name of the binding can't be set since there is no index found (-1)

Fixes: #444 

tbarlow12: @mikedingjan thanks for the fix! Any way we can get a unit test or two to validate the change?
mikedebock: @tbarlow12 Thank you for your feedback. I'm also waiting for this fix, because of that I added the unittest :) 
tbarlow12: @mikedingjan and @mikedebock thanks for the help here. This is the 2nd issue I've seen relating to binding creation, and it might be an issue with the backwards compatibility of `x-azure-settings`. You should be able to bring everything up one level and remove that property entirely. But I'll investigate further when I get some time

Patch:
diff --git a/src/services/packageService.ts b/src/services/packageService.ts
index dc5d03c..b2660ea 100644
--- a/src/services/packageService.ts
+++ b/src/services/packageService.ts
@@ -108,7 +108,7 @@ export class PackageService extends BaseService {
           rimraf.sync(folderPath);
         }
       });
-      
+
       // Delete function folder if empty
       const items = fs.readdirSync(functionName);
       if (items.length === 0) {
@@ -122,7 +122,7 @@ export class PackageService extends BaseService {
         fs.unlinkSync(filePath);
       }
     }
-    
+
     for (const dir of rootFoldersToRemove) {
       const dirPath = path.join(this.serverless.config.servicePath, dir);
       if (fs.existsSync(dirPath)) {
@@ -151,14 +151,16 @@ export class PackageService extends BaseService {
     if (this.configService.isPythonTarget()) {
       const index = (functionJSON.bindings as any[])
         .findIndex((binding) => (!binding.direction || binding.direction === "out"));
-      functionJSON.bindings[index].name = "$return";
-    } else {
+
+      if (functionJSON.bindings[index]) {
+        functionJSON.bindings[index].name = "$return";
+      }
     }
     functionJSON.scriptFile = handlerPath;
 
     const functionObject = this.configService.getFunctionConfig()[functionName];
     const incomingBinding = Utils.getIncomingBindingConfig(functionObject);
-    
+
     const bindingAzureSettings = Utils.get(incomingBinding, constants.xAzureSettings, incomingBinding);
 
     if (bindingAzureSettings.route) {
@@ -166,7 +168,9 @@ export class PackageService extends BaseService {
       const index = (functionJSON.bindings as any[])
         .findIndex((binding) => (!binding.direction || binding.direction === "in"));
 
-      functionJSON.bindings[index].route = bindingAzureSettings.route;
+      if (functionJSON.bindings[index]) {
+        functionJSON.bindings[index].route = bindingAzureSettings.route;
+      }
     }
 
     return functionJSON;


Test patch:
diff --git a/src/services/packageService.test.ts b/src/services/packageService.test.ts
index 8c5141e..3713f5e 100644
--- a/src/services/packageService.test.ts
+++ b/src/services/packageService.test.ts
@@ -5,6 +5,7 @@ import Serverless from "serverless";
 import { FunctionMetadata } from "../shared/utils";
 import { MockFactory } from "../test/mockFactory";
 import { PackageService } from "./packageService";
+import { Runtime } from "../config/runtime";
 
 jest.mock("rimraf");
 import rimraf from "rimraf";
@@ -228,6 +229,32 @@ describe("Package Service", () => {
     writeFileSpy.mockRestore();
   });
 
+  it("createBinding should be able to create function.json without bindings", async () => {
+    // Create service provider with python 3.8 runtime
+    const provider = MockFactory.createTestAzureServiceProvider()
+    provider.runtime = Runtime.PYTHON38
+    sls = MockFactory.createTestServerless({"service": { "provider": provider }});
+    sls.config.servicePath = process.cwd();
+    sls.service["functions"] = {
+      hello: MockFactory.createTestAzureFunctionConfig(functionRoute),
+      eventhubHandler: MockFactory.createTestEventHubFunctionConfig(),
+    }
+
+    const functionName = "hello";
+    const functionMetadata: FunctionMetadata = {
+      entryPoint: "handler",
+      handlerPath: "src/handlers/hello",
+      params: {
+        functionJson: {
+          bindings: []
+        },
+      },
+    };
+
+    packageService = new PackageService(sls, MockFactory.createTestServerlessOptions());
+    await packageService.createBinding(functionName, functionMetadata);
+  });
+
   it("webpack copies required", async () => {
     mockFs({
       // Generated by webpack plugin