Repository: serverless/serverless-azure-functions
Pull request #642 (2023-02-23 09:07:11)

Adding support for nodejs16 and nodejs18
<!--
1. Please check out and follow our Contributing Guidelines: https://github.com/serverless/serverless-azure-functions/blob/master/CONTRIBUTING.md
2. Do not remove any section of the template. If something is not applicable leave it empty but leave it in the PR
3. Please follow the template, otherwise we'll have to ask you to update it and it will take longer until your PR is merged
-->

## What did you implement:

Adding support for Nodejs 18

<!--
Briefly describe the feature if no issue exists for this PR
-->

## How did you implement it:

Following a template that others have followed

<!--
If this is a nontrivial change please briefly describe your implementation so it's easy for us to understand and review your code.
-->

## How can we verify it:

Use it to deploy a nodejs18 function app to Azure.

<!--
Add any applicable config, commands, screenshots or other resources
to make it easy for us to verify this works. The easier you make it for us
to review a PR, the faster we can review and merge it.

Examples:
* serverless.yml - Fully functioning to easily deploy changes
* Screenshots - Showing the difference between your output and the master
* Cloud Configuration - List cloud resources and show that the correct configuration is in place
* Other - Anything else that comes to mind to help us evaluate
-->

## Todos:

_**Note: Run `npm run test:ci` to run all validation checks on proposed changes**_

- [x] Ensure there are no lint errors.  
       **Validate via `npm run lint`**  
       _Note: Some reported issues can be automatically fixed by running `npm run lint:fix`_
- [x] Write tests and confirm existing functionality is not broken.  
       **Validate via `npm test`**
- [x] Write documentation
- [x] Provide verification config / commands / resources
- [x] Enable "Allow edits from maintainers" for this PR
- [x] Update the messages below

**_Is this ready for review?:_** YES
**_Is it a breaking change?:_** NO


gligorkot: @medikoo this is now updated and ready for re-review

Patch:
diff --git a/src/config/runtime.ts b/src/config/runtime.ts
index 7fc37fb..a77b684 100644
--- a/src/config/runtime.ts
+++ b/src/config/runtime.ts
@@ -4,6 +4,7 @@ export enum Runtime {
   NODE12 = "nodejs12",
   NODE14 = "nodejs14",
   NODE16 = "nodejs16",
+  NODE18 = "nodejs18",
   PYTHON36 = "python3.6",
   PYTHON37 = "python3.7",
   PYTHON38 = "python3.8",
@@ -16,6 +17,7 @@ export const supportedRuntimes = [
   Runtime.NODE12,
   Runtime.NODE14,
   Runtime.NODE16,
+  Runtime.NODE18,
   Runtime.PYTHON36,
   Runtime.PYTHON37,
   Runtime.PYTHON38,
@@ -95,6 +97,7 @@ export const dockerImages = {
   nodejs12: "NODE|12",
   nodejs14: "NODE|14",
   nodejs16: "NODE|16",
+  nodejs18: "NODE|18",
   "python3.6": "PYTHON|3.6",
   "python3.7": "PYTHON|3.7",
   "python3.8": "PYTHON|3.8",


Test patch:
diff --git a/src/armTemplates/resources/functionApp.test.ts b/src/armTemplates/resources/functionApp.test.ts
index 9945439..c280e1b 100644
--- a/src/armTemplates/resources/functionApp.test.ts
+++ b/src/armTemplates/resources/functionApp.test.ts
@@ -231,6 +231,23 @@ describe("Function App Resource", () => {
         expect(functionAppNodeVersion.value).toEqual("~16");
       });
 
+      it("gets correct parameters - node 18", () => {
+        const config = getConfig(FunctionAppOS.LINUX, Runtime.NODE18);
+
+        const resource = new FunctionAppResource();
+
+        const params = resource.getParameters(config);
+        const {
+          linuxFxVersion,
+          functionAppNodeVersion,
+        } = params;
+
+        assertLinuxParams(params);
+
+        expect(linuxFxVersion.value).toEqual("NODE|18");
+        expect(functionAppNodeVersion.value).toEqual("~18");
+      });
+
       it("gets correct parameters - python 3.6", () => {
         const config = getConfig(FunctionAppOS.LINUX, Runtime.PYTHON36);
     
diff --git a/src/config/runtime.test.ts b/src/config/runtime.test.ts
index a1e0e53..b4835ea 100644
--- a/src/config/runtime.test.ts
+++ b/src/config/runtime.test.ts
@@ -7,6 +7,7 @@ describe("Runtime", () => {
     expect(isNodeRuntime(Runtime.NODE12)).toBe(true);
     expect(isNodeRuntime(Runtime.NODE14)).toBe(true);
     expect(isNodeRuntime(Runtime.NODE16)).toBe(true);
+    expect(isNodeRuntime(Runtime.NODE18)).toBe(true);
     expect(isNodeRuntime(Runtime.PYTHON36)).toBe(false);
     expect(isNodeRuntime(Runtime.PYTHON37)).toBe(false);
     expect(isNodeRuntime(Runtime.PYTHON38)).toBe(false);
@@ -17,6 +18,7 @@ describe("Runtime", () => {
     expect(isPythonRuntime(Runtime.NODE12)).toBe(false);
     expect(isPythonRuntime(Runtime.NODE14)).toBe(false);
     expect(isPythonRuntime(Runtime.NODE16)).toBe(false);
+    expect(isPythonRuntime(Runtime.NODE18)).toBe(false);
     expect(isPythonRuntime(Runtime.PYTHON36)).toBe(true);
     expect(isPythonRuntime(Runtime.PYTHON37)).toBe(true);
     expect(isPythonRuntime(Runtime.PYTHON38)).toBe(true);
@@ -27,6 +29,7 @@ describe("Runtime", () => {
     expect(getRuntimeVersion(Runtime.NODE12)).toBe("12");
     expect(getRuntimeVersion(Runtime.NODE14)).toBe("14");
     expect(getRuntimeVersion(Runtime.NODE16)).toBe("16");
+    expect(getRuntimeVersion(Runtime.NODE18)).toBe("18");
     expect(getRuntimeVersion(Runtime.PYTHON36)).toBe("3.6");
     expect(getRuntimeVersion(Runtime.PYTHON37)).toBe("3.7");
     expect(getRuntimeVersion(Runtime.PYTHON38)).toBe("3.8");
@@ -43,6 +46,7 @@ describe("Runtime", () => {
     expect(getRuntimeLanguage(Runtime.NODE12)).toBe("nodejs");
     expect(getRuntimeLanguage(Runtime.NODE14)).toBe("nodejs");
     expect(getRuntimeLanguage(Runtime.NODE16)).toBe("nodejs");
+    expect(getRuntimeLanguage(Runtime.NODE18)).toBe("nodejs");
     expect(getRuntimeLanguage(Runtime.PYTHON36)).toBe("python");
     expect(getRuntimeLanguage(Runtime.PYTHON37)).toBe("python");
     expect(getRuntimeLanguage(Runtime.PYTHON38)).toBe("python");
@@ -59,6 +63,7 @@ describe("Runtime", () => {
     expect(getFunctionWorkerRuntime(Runtime.NODE12)).toBe("node");
     expect(getFunctionWorkerRuntime(Runtime.NODE14)).toBe("node");
     expect(getFunctionWorkerRuntime(Runtime.NODE16)).toBe("node");
+    expect(getFunctionWorkerRuntime(Runtime.NODE18)).toBe("node");
     expect(getFunctionWorkerRuntime(Runtime.PYTHON36)).toBe("python");
     expect(getFunctionWorkerRuntime(Runtime.PYTHON37)).toBe("python");
     expect(getFunctionWorkerRuntime(Runtime.PYTHON38)).toBe("python");
diff --git a/src/services/configService.test.ts b/src/services/configService.test.ts
index 4a61b38..803c812 100644
--- a/src/services/configService.test.ts
+++ b/src/services/configService.test.ts
@@ -225,7 +225,7 @@ describe("Config Service", () => {
         sls.service.provider.runtime = "python2.7" as any;
         expect(() => new ConfigService(sls, {} as any))
           .toThrowError("Runtime python2.7 is not supported. " +
-            "Runtimes supported: nodejs10,nodejs12,nodejs14,nodejs16,python3.6,python3.7,python3.8");
+            "Runtimes supported: nodejs10,nodejs12,nodejs14,nodejs16,nodejs18,python3.6,python3.7,python3.8");
       });
 
       it("throws error when incomplete nodejs version in defined", () => {
@@ -233,7 +233,7 @@ describe("Config Service", () => {
         sls.service.provider.runtime = "nodejs" as any;
         expect(() => new ConfigService(sls, {} as any))
           .toThrowError("Runtime nodejs is not supported. " +
-            "Runtimes supported: nodejs10,nodejs12,nodejs14,nodejs16,python3.6,python3.7,python3.8");
+            "Runtimes supported: nodejs10,nodejs12,nodejs14,nodejs16,nodejs18,python3.6,python3.7,python3.8");
       });
 
       it("throws error when unsupported nodejs version in defined", () => {
@@ -241,7 +241,7 @@ describe("Config Service", () => {
         sls.service.provider.runtime = "nodejs5.x" as any;
         expect(() => new ConfigService(sls, {} as any))
           .toThrowError("Runtime nodejs5.x is not supported. " +
-            "Runtimes supported: nodejs10,nodejs12,nodejs14,nodejs16,python3.6,python3.7,python3.8");
+            "Runtimes supported: nodejs10,nodejs12,nodejs14,nodejs16,nodejs18,python3.6,python3.7,python3.8");
       });
 
       it("Does not throw an error when valid nodejs version is defined", () => {
@@ -258,7 +258,7 @@ describe("Config Service", () => {
         sls.service.provider.runtime = undefined;
         expect(() => new ConfigService(sls, {} as any))
           .toThrowError("Runtime undefined. " +
-            "Runtimes supported: nodejs10,nodejs12,nodejs14,nodejs16,python3.6,python3.7,python3.8");
+            "Runtimes supported: nodejs10,nodejs12,nodejs14,nodejs16,nodejs18,python3.6,python3.7,python3.8");
       });
 
       it("does not throw an error with python3.6", () => {