Dynamically retrieve .NET templates (#457)

This commit is contained in:
Eric Jizba 2018-07-17 16:12:42 -07:00 коммит произвёл GitHub
Родитель 72477583ab
Коммит 3c65d5596b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
55 изменённых файлов: 1991 добавлений и 905 удалений

5
.gitignore поставляемый
Просмотреть файл

@ -63,4 +63,7 @@ package-lock.json
# Output
out
*.vsix
.vscode-test
.vscode-test
# debugging artifacts
resources/dotnetTemplates

Просмотреть файл

@ -128,15 +128,6 @@ brew install azure-functions-core-tools
* [VS Code Debugger for C#](https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp)
* [.NET CLI](https://docs.microsoft.com/dotnet/core/tools/?tabs=netcore2x)
* .NET Templates for Azure Functions
* You will be automatically prompted to install these templates when you first create a project/function
* If you are using v2.0 of the Azure Functions runtime, you must install the beta (.NET Core) templates
* If you are using v1.0 of the Azure Functions runtime, you must install the v1.0 (.NET Framework) templates.
> **NOTE**: The VS Code Debugger for C# [only supports](https://github.com/OmniSharp/omnisharp-vscode/issues/1716) attaching to 64-bit processes. v1.0 of the Azure Functions runtime defaults to 32-bit and you must install a 64-bit version. See [here](https://aka.ms/azFunc64bit) for instructions.
* You may uninstall or reinstall the templates with the following steps:
1. Open Command Palette (View -> Command Palette...)
1. Search for "Azure Functions" and "install" or "uninstall"
1. Run the corresponding command for .NET templates
> **NOTE**: The default experience for C# uses class libraries (*.cs files), which provide superior performance, scalability, and versatility over C# Scripts (*.csx files). If you want to use C# Scripts, you may change your `azureFunctions.projectLanguage` user setting to `C#Script`.

Просмотреть файл

@ -54,7 +54,6 @@
"onCommand:azureFunctions.appSettings.encrypt",
"onCommand:azureFunctions.appSettings.decrypt",
"onCommand:azureFunctions.pickProcess",
"onCommand:azureFunctions.uninstallDotnetTemplates",
"onCommand:azureFunctions.startStreamingLogs",
"onCommand:azureFunctions.stopStreamingLogs",
"onCommand:azureFunctions.deleteProxy",
@ -215,11 +214,6 @@
"title": "%azFunc.pickProcess%",
"category": "Azure Functions"
},
{
"command": "azureFunctions.uninstallDotnetTemplates",
"title": "%azFunc.uninstallDotnetTemplates%",
"category": "Azure Functions"
},
{
"command": "azureFunctions.startStreamingLogs",
"title": "%azFunc.startStreamingLogs%",

Просмотреть файл

@ -30,8 +30,6 @@
"azFunc.appSettings.encrypt": "Encrypt Settings",
"azFunc.pickProcess": "Pick Process",
"azFunc.deploySubpathDescription": "The default subpath of a workspace folder to use when deploying.",
"azFunc.installDotnetTemplates": "Install templates for the .NET CLI",
"azFunc.uninstallDotnetTemplates": "Uninstall templates for the .NET CLI",
"azFunc.showCoreToolsWarningDescription": "Show a warning if your installed version of Azure Functions Core Tools is out-of-date.",
"azFunc.show64BitWarningDescription": "Show a warning to install a 64-bit version of the Azure Functions Core Tools when you create a .NET Framework project.",
"azFunc.showProjectWarningDescription": "Show a warning when an Azure Functions project was detected that has not been initialized for use in VS Code.",

Двоичные данные
resources/dotnetJsonCli/Microsoft.DotNet.Cli.CommandLine.dll Executable file

Двоичный файл не отображается.

Двоичные данные
resources/dotnetJsonCli/Microsoft.TemplateEngine.Abstractions.dll Executable file

Двоичный файл не отображается.

Двоичные данные
resources/dotnetJsonCli/Microsoft.TemplateEngine.Cli.dll Executable file

Двоичный файл не отображается.

Двоичные данные
resources/dotnetJsonCli/Microsoft.TemplateEngine.Core.Contracts.dll Executable file

Двоичный файл не отображается.

Двоичные данные
resources/dotnetJsonCli/Microsoft.TemplateEngine.Core.dll Executable file

Двоичный файл не отображается.

Двоичные данные
resources/dotnetJsonCli/Microsoft.TemplateEngine.Edge.dll Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,995 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v2.0",
"signature": "12ab36320203a93d9a46b7b16769f227b28d545e"
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v2.0": {
"Microsoft.TemplateEngine.JsonCli/1.0.0": {
"dependencies": {
"Microsoft.TemplateEngine.Cli": "1.0.1-beta3-20180212-1375715",
"Microsoft.TemplateEngine.Orchestrator.RunnableProjects": "1.0.1-beta3-20180212-1375715"
},
"runtime": {
"Microsoft.TemplateEngine.JsonCli.dll": {}
}
},
"Microsoft.CSharp/4.0.1": {
"dependencies": {
"System.Collections": "4.3.0",
"System.Diagnostics.Debug": "4.3.0",
"System.Dynamic.Runtime": "4.0.11",
"System.Globalization": "4.3.0",
"System.Linq": "4.1.0",
"System.Linq.Expressions": "4.1.0",
"System.ObjectModel": "4.0.12",
"System.Reflection": "4.3.0",
"System.Reflection.Extensions": "4.3.0",
"System.Reflection.Primitives": "4.3.0",
"System.Reflection.TypeExtensions": "4.1.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Extensions": "4.3.0",
"System.Runtime.InteropServices": "4.3.0",
"System.Threading": "4.3.0"
}
},
"Microsoft.DotNet.Cli.CommandLine/0.1.0-alpha-142": {
"runtime": {
"lib/netstandard1.5/Microsoft.DotNet.Cli.CommandLine.dll": {
"assemblyVersion": "0.1.0.0",
"fileVersion": "0.1.0.0"
}
}
},
"Microsoft.NETCore.Targets/1.1.0": {},
"Microsoft.TemplateEngine.Abstractions/1.0.1-beta3-20180212-1375715": {
"runtime": {
"lib/netstandard1.3/Microsoft.TemplateEngine.Abstractions.dll": {
"assemblyVersion": "1.0.1.0",
"fileVersion": "1.0.1.0"
}
}
},
"Microsoft.TemplateEngine.Cli/1.0.1-beta3-20180212-1375715": {
"dependencies": {
"Microsoft.DotNet.Cli.CommandLine": "0.1.0-alpha-142",
"Microsoft.TemplateEngine.Abstractions": "1.0.1-beta3-20180212-1375715",
"Microsoft.TemplateEngine.Edge": "1.0.1-beta3-20180212-1375715",
"Microsoft.TemplateEngine.Utils": "1.0.1-beta3-20180212-1375715",
"Newtonsoft.Json": "9.0.1",
"System.Diagnostics.Process": "4.3.0"
},
"runtime": {
"lib/netstandard1.5/Microsoft.TemplateEngine.Cli.dll": {
"assemblyVersion": "1.0.1.0",
"fileVersion": "1.0.1.0"
}
}
},
"Microsoft.TemplateEngine.Core/1.0.1-beta3-20180212-1375715": {
"dependencies": {
"Microsoft.TemplateEngine.Abstractions": "1.0.1-beta3-20180212-1375715",
"Microsoft.TemplateEngine.Core.Contracts": "1.0.1-beta3-20180212-1375715",
"Microsoft.TemplateEngine.Utils": "1.0.1-beta3-20180212-1375715",
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0"
},
"runtime": {
"lib/netstandard1.3/Microsoft.TemplateEngine.Core.dll": {
"assemblyVersion": "1.0.1.0",
"fileVersion": "1.0.1.0"
}
}
},
"Microsoft.TemplateEngine.Core.Contracts/1.0.1-beta3-20180212-1375715": {
"dependencies": {
"Microsoft.TemplateEngine.Abstractions": "1.0.1-beta3-20180212-1375715"
},
"runtime": {
"lib/netstandard1.3/Microsoft.TemplateEngine.Core.Contracts.dll": {
"assemblyVersion": "1.0.1.0",
"fileVersion": "1.0.1.0"
}
}
},
"Microsoft.TemplateEngine.Edge/1.0.1-beta3-20180212-1375715": {
"dependencies": {
"Microsoft.TemplateEngine.Abstractions": "1.0.1-beta3-20180212-1375715",
"Microsoft.TemplateEngine.Utils": "1.0.1-beta3-20180212-1375715",
"Newtonsoft.Json": "9.0.1",
"System.IO.Compression": "4.3.0",
"System.Runtime.Loader": "4.3.0"
},
"runtime": {
"lib/netstandard1.5/Microsoft.TemplateEngine.Edge.dll": {
"assemblyVersion": "1.0.1.0",
"fileVersion": "1.0.1.0"
}
}
},
"Microsoft.TemplateEngine.Orchestrator.RunnableProjects/1.0.1-beta3-20180212-1375715": {
"dependencies": {
"Microsoft.TemplateEngine.Abstractions": "1.0.1-beta3-20180212-1375715",
"Microsoft.TemplateEngine.Core": "1.0.1-beta3-20180212-1375715",
"Microsoft.TemplateEngine.Core.Contracts": "1.0.1-beta3-20180212-1375715",
"Microsoft.TemplateEngine.Utils": "1.0.1-beta3-20180212-1375715",
"Newtonsoft.Json": "9.0.1"
},
"runtime": {
"lib/netstandard1.3/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.dll": {
"assemblyVersion": "1.0.1.0",
"fileVersion": "1.0.1.0"
}
}
},
"Microsoft.TemplateEngine.Utils/1.0.1-beta3-20180212-1375715": {
"dependencies": {
"Microsoft.TemplateEngine.Abstractions": "1.0.1-beta3-20180212-1375715",
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0"
},
"runtime": {
"lib/netstandard1.3/Microsoft.TemplateEngine.Utils.dll": {
"assemblyVersion": "1.0.1.0",
"fileVersion": "1.0.1.0"
}
}
},
"Microsoft.Win32.Primitives/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
}
},
"Microsoft.Win32.Registry/4.3.0": {
"dependencies": {
"System.Collections": "4.3.0",
"System.Globalization": "4.3.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Extensions": "4.3.0",
"System.Runtime.Handles": "4.3.0",
"System.Runtime.InteropServices": "4.3.0"
},
"runtimeTargets": {
"runtime/unix/lib/_._": {
"rid": "unix",
"assetType": "runtime"
},
"runtime/win/lib/_._": {
"rid": "win",
"assetType": "runtime"
}
}
},
"Newtonsoft.Json/9.0.1": {
"dependencies": {
"Microsoft.CSharp": "4.0.1",
"System.Collections": "4.3.0",
"System.Diagnostics.Debug": "4.3.0",
"System.Dynamic.Runtime": "4.0.11",
"System.Globalization": "4.3.0",
"System.IO": "4.3.0",
"System.Linq": "4.1.0",
"System.Linq.Expressions": "4.1.0",
"System.ObjectModel": "4.0.12",
"System.Reflection": "4.3.0",
"System.Reflection.Extensions": "4.3.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Extensions": "4.3.0",
"System.Runtime.Serialization.Primitives": "4.1.1",
"System.Text.Encoding": "4.3.0",
"System.Text.Encoding.Extensions": "4.3.0",
"System.Text.RegularExpressions": "4.1.0",
"System.Threading": "4.3.0",
"System.Threading.Tasks": "4.3.0",
"System.Xml.ReaderWriter": "4.0.11",
"System.Xml.XDocument": "4.0.11"
},
"runtime": {
"lib/netstandard1.0/Newtonsoft.Json.dll": {
"assemblyVersion": "9.0.0.0",
"fileVersion": "9.0.1.19813"
}
}
},
"runtime.native.System/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0"
}
},
"runtime.native.System.IO.Compression/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0"
}
},
"System.Buffers/4.3.0": {
"dependencies": {
"System.Diagnostics.Debug": "4.3.0",
"System.Diagnostics.Tracing": "4.3.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Threading": "4.3.0"
}
},
"System.Collections/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
}
},
"System.Diagnostics.Debug/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
}
},
"System.Diagnostics.Process/4.3.0": {
"dependencies": {
"Microsoft.Win32.Primitives": "4.3.0",
"Microsoft.Win32.Registry": "4.3.0",
"System.Collections": "4.3.0",
"System.Diagnostics.Debug": "4.3.0",
"System.Globalization": "4.3.0",
"System.IO": "4.3.0",
"System.IO.FileSystem": "4.3.0",
"System.IO.FileSystem.Primitives": "4.3.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Extensions": "4.3.0",
"System.Runtime.Handles": "4.3.0",
"System.Runtime.InteropServices": "4.3.0",
"System.Text.Encoding": "4.3.0",
"System.Text.Encoding.Extensions": "4.3.0",
"System.Threading": "4.3.0",
"System.Threading.Tasks": "4.3.0",
"System.Threading.Thread": "4.3.0",
"System.Threading.ThreadPool": "4.3.0",
"runtime.native.System": "4.3.0"
},
"runtimeTargets": {
"runtime/linux/lib/_._": {
"rid": "linux",
"assetType": "runtime"
},
"runtime/osx/lib/_._": {
"rid": "osx",
"assetType": "runtime"
},
"runtime/win/lib/_._": {
"rid": "win",
"assetType": "runtime"
}
}
},
"System.Diagnostics.Tools/4.0.1": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
}
},
"System.Diagnostics.Tracing/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
}
},
"System.Dynamic.Runtime/4.0.11": {
"dependencies": {
"System.Collections": "4.3.0",
"System.Diagnostics.Debug": "4.3.0",
"System.Globalization": "4.3.0",
"System.Linq": "4.1.0",
"System.Linq.Expressions": "4.1.0",
"System.ObjectModel": "4.0.12",
"System.Reflection": "4.3.0",
"System.Reflection.Emit": "4.0.1",
"System.Reflection.Emit.ILGeneration": "4.0.1",
"System.Reflection.Primitives": "4.3.0",
"System.Reflection.TypeExtensions": "4.1.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Extensions": "4.3.0",
"System.Threading": "4.3.0"
}
},
"System.Globalization/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
}
},
"System.IO/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0",
"System.Text.Encoding": "4.3.0",
"System.Threading.Tasks": "4.3.0"
}
},
"System.IO.Compression/4.3.0": {
"dependencies": {
"System.Buffers": "4.3.0",
"System.Collections": "4.3.0",
"System.Diagnostics.Debug": "4.3.0",
"System.IO": "4.3.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Extensions": "4.3.0",
"System.Runtime.Handles": "4.3.0",
"System.Runtime.InteropServices": "4.3.0",
"System.Text.Encoding": "4.3.0",
"System.Threading": "4.3.0",
"System.Threading.Tasks": "4.3.0",
"runtime.native.System": "4.3.0",
"runtime.native.System.IO.Compression": "4.3.0"
},
"runtimeTargets": {
"runtime/unix/lib/_._": {
"rid": "unix",
"assetType": "runtime"
},
"runtime/win/lib/_._": {
"rid": "win",
"assetType": "runtime"
}
}
},
"System.IO.FileSystem/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.IO": "4.3.0",
"System.IO.FileSystem.Primitives": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Handles": "4.3.0",
"System.Text.Encoding": "4.3.0",
"System.Threading.Tasks": "4.3.0"
}
},
"System.IO.FileSystem.Primitives/4.3.0": {
"dependencies": {
"System.Runtime": "4.3.0"
}
},
"System.Linq/4.1.0": {
"dependencies": {
"System.Collections": "4.3.0",
"System.Diagnostics.Debug": "4.3.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Extensions": "4.3.0"
}
},
"System.Linq.Expressions/4.1.0": {
"dependencies": {
"System.Collections": "4.3.0",
"System.Diagnostics.Debug": "4.3.0",
"System.Globalization": "4.3.0",
"System.IO": "4.3.0",
"System.Linq": "4.1.0",
"System.ObjectModel": "4.0.12",
"System.Reflection": "4.3.0",
"System.Reflection.Emit": "4.0.1",
"System.Reflection.Emit.ILGeneration": "4.0.1",
"System.Reflection.Emit.Lightweight": "4.0.1",
"System.Reflection.Extensions": "4.3.0",
"System.Reflection.Primitives": "4.3.0",
"System.Reflection.TypeExtensions": "4.1.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Extensions": "4.3.0",
"System.Threading": "4.3.0"
}
},
"System.ObjectModel/4.0.12": {
"dependencies": {
"System.Collections": "4.3.0",
"System.Diagnostics.Debug": "4.3.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Threading": "4.3.0"
}
},
"System.Reflection/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.IO": "4.3.0",
"System.Reflection.Primitives": "4.3.0",
"System.Runtime": "4.3.0"
}
},
"System.Reflection.Emit/4.0.1": {
"dependencies": {
"System.IO": "4.3.0",
"System.Reflection": "4.3.0",
"System.Reflection.Emit.ILGeneration": "4.0.1",
"System.Reflection.Primitives": "4.3.0",
"System.Runtime": "4.3.0"
}
},
"System.Reflection.Emit.ILGeneration/4.0.1": {
"dependencies": {
"System.Reflection": "4.3.0",
"System.Reflection.Primitives": "4.3.0",
"System.Runtime": "4.3.0"
}
},
"System.Reflection.Emit.Lightweight/4.0.1": {
"dependencies": {
"System.Reflection": "4.3.0",
"System.Reflection.Emit.ILGeneration": "4.0.1",
"System.Reflection.Primitives": "4.3.0",
"System.Runtime": "4.3.0"
}
},
"System.Reflection.Extensions/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Reflection": "4.3.0",
"System.Runtime": "4.3.0"
}
},
"System.Reflection.Primitives/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
}
},
"System.Reflection.TypeExtensions/4.1.0": {
"dependencies": {
"System.Reflection": "4.3.0",
"System.Runtime": "4.3.0"
}
},
"System.Resources.ResourceManager/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Globalization": "4.3.0",
"System.Reflection": "4.3.0",
"System.Runtime": "4.3.0"
}
},
"System.Runtime/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0"
}
},
"System.Runtime.Extensions/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
}
},
"System.Runtime.Handles/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
}
},
"System.Runtime.InteropServices/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Reflection": "4.3.0",
"System.Reflection.Primitives": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Handles": "4.3.0"
}
},
"System.Runtime.InteropServices.RuntimeInformation/4.3.0": {
"dependencies": {
"System.Reflection": "4.3.0",
"System.Reflection.Extensions": "4.3.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.InteropServices": "4.3.0",
"System.Threading": "4.3.0",
"runtime.native.System": "4.3.0"
},
"runtimeTargets": {
"runtime/unix/lib/_._": {
"rid": "unix",
"assetType": "runtime"
},
"runtime/win/lib/_._": {
"rid": "win",
"assetType": "runtime"
}
}
},
"System.Runtime.Loader/4.3.0": {
"dependencies": {
"System.IO": "4.3.0",
"System.Reflection": "4.3.0",
"System.Runtime": "4.3.0"
}
},
"System.Runtime.Serialization.Primitives/4.1.1": {
"dependencies": {
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0"
}
},
"System.Text.Encoding/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
}
},
"System.Text.Encoding.Extensions/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0",
"System.Text.Encoding": "4.3.0"
}
},
"System.Text.RegularExpressions/4.1.0": {
"dependencies": {
"System.Collections": "4.3.0",
"System.Globalization": "4.3.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Extensions": "4.3.0",
"System.Threading": "4.3.0"
}
},
"System.Threading/4.3.0": {
"dependencies": {
"System.Runtime": "4.3.0",
"System.Threading.Tasks": "4.3.0"
}
},
"System.Threading.Tasks/4.3.0": {
"dependencies": {
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
}
},
"System.Threading.Tasks.Extensions/4.0.0": {
"dependencies": {
"System.Collections": "4.3.0",
"System.Runtime": "4.3.0",
"System.Threading.Tasks": "4.3.0"
}
},
"System.Threading.Thread/4.3.0": {
"dependencies": {
"System.Runtime": "4.3.0"
}
},
"System.Threading.ThreadPool/4.3.0": {
"dependencies": {
"System.Runtime": "4.3.0",
"System.Runtime.Handles": "4.3.0"
}
},
"System.Xml.ReaderWriter/4.0.11": {
"dependencies": {
"System.Collections": "4.3.0",
"System.Diagnostics.Debug": "4.3.0",
"System.Globalization": "4.3.0",
"System.IO": "4.3.0",
"System.IO.FileSystem": "4.3.0",
"System.IO.FileSystem.Primitives": "4.3.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Extensions": "4.3.0",
"System.Runtime.InteropServices": "4.3.0",
"System.Text.Encoding": "4.3.0",
"System.Text.Encoding.Extensions": "4.3.0",
"System.Text.RegularExpressions": "4.1.0",
"System.Threading.Tasks": "4.3.0",
"System.Threading.Tasks.Extensions": "4.0.0"
}
},
"System.Xml.XDocument/4.0.11": {
"dependencies": {
"System.Collections": "4.3.0",
"System.Diagnostics.Debug": "4.3.0",
"System.Diagnostics.Tools": "4.0.1",
"System.Globalization": "4.3.0",
"System.IO": "4.3.0",
"System.Reflection": "4.3.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Extensions": "4.3.0",
"System.Text.Encoding": "4.3.0",
"System.Threading": "4.3.0",
"System.Xml.ReaderWriter": "4.0.11"
}
}
}
},
"libraries": {
"Microsoft.TemplateEngine.JsonCli/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"Microsoft.CSharp/4.0.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-17h8b5mXa87XYKrrVqdgZ38JefSUqLChUQpXgSnpzsM0nDOhE40FTeNWOJ/YmySGV6tG6T8+hjz6vxbknHJr6A==",
"path": "microsoft.csharp/4.0.1",
"hashPath": "microsoft.csharp.4.0.1.nupkg.sha512"
},
"Microsoft.DotNet.Cli.CommandLine/0.1.0-alpha-142": {
"type": "package",
"serviceable": true,
"sha512": "sha512-cJRQ8wRchiVercqc9XsdWRljurEvPgY4fhzUZtb8/wDpkkVX/9TyospjC7ZacGvtXtkY8hRubnOwfBvAIZpMeg==",
"path": "microsoft.dotnet.cli.commandline/0.1.0-alpha-142",
"hashPath": "microsoft.dotnet.cli.commandline.0.1.0-alpha-142.nupkg.sha512"
},
"Microsoft.NETCore.Targets/1.1.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==",
"path": "microsoft.netcore.targets/1.1.0",
"hashPath": "microsoft.netcore.targets.1.1.0.nupkg.sha512"
},
"Microsoft.TemplateEngine.Abstractions/1.0.1-beta3-20180212-1375715": {
"type": "package",
"serviceable": true,
"sha512": "sha512-3KigJHcuZDDkG/s4WPwelH4jeGOp29+Np28QFkX109umkoSMRXn4MCWzyd0t/aQB5+Fdi+U2cOL1qjBFuOrB0A==",
"path": "microsoft.templateengine.abstractions/1.0.1-beta3-20180212-1375715",
"hashPath": "microsoft.templateengine.abstractions.1.0.1-beta3-20180212-1375715.nupkg.sha512"
},
"Microsoft.TemplateEngine.Cli/1.0.1-beta3-20180212-1375715": {
"type": "package",
"serviceable": true,
"sha512": "sha512-aBwLxeBt8Mvi3icI11A8q+QVgZ22VOOnP0P9DwxZnQJ1EaBAgiECgLiiNrxO3TdyJwb5e2t1jk0LHpUmQTnRxA==",
"path": "microsoft.templateengine.cli/1.0.1-beta3-20180212-1375715",
"hashPath": "microsoft.templateengine.cli.1.0.1-beta3-20180212-1375715.nupkg.sha512"
},
"Microsoft.TemplateEngine.Core/1.0.1-beta3-20180212-1375715": {
"type": "package",
"serviceable": true,
"sha512": "sha512-uaBQSzvnA5g4wkUlFU2rRMREDsXN4qaWZE9LDOphCBtO2Yfx73ce952MSHGki2uoAMCCgxPMUurzJJAcklD8HA==",
"path": "microsoft.templateengine.core/1.0.1-beta3-20180212-1375715",
"hashPath": "microsoft.templateengine.core.1.0.1-beta3-20180212-1375715.nupkg.sha512"
},
"Microsoft.TemplateEngine.Core.Contracts/1.0.1-beta3-20180212-1375715": {
"type": "package",
"serviceable": true,
"sha512": "sha512-hdUxrkjuSVIpcjLW2UwsxepSUnmMH8hjd9TLNwEuZhJOM24A6/Qs2op7NRAGf1AfF6bTb/XbXCAiy8sJxbskGw==",
"path": "microsoft.templateengine.core.contracts/1.0.1-beta3-20180212-1375715",
"hashPath": "microsoft.templateengine.core.contracts.1.0.1-beta3-20180212-1375715.nupkg.sha512"
},
"Microsoft.TemplateEngine.Edge/1.0.1-beta3-20180212-1375715": {
"type": "package",
"serviceable": true,
"sha512": "sha512-kR9ZEXdkkpTsZIK2IF6DiX0JG1vCwj+8cp+/MedcPCLpHyx0sloo5sMAawAv8CIzpd85ZcdpMSiy+fVTSRcZTA==",
"path": "microsoft.templateengine.edge/1.0.1-beta3-20180212-1375715",
"hashPath": "microsoft.templateengine.edge.1.0.1-beta3-20180212-1375715.nupkg.sha512"
},
"Microsoft.TemplateEngine.Orchestrator.RunnableProjects/1.0.1-beta3-20180212-1375715": {
"type": "package",
"serviceable": true,
"sha512": "sha512-rUXaRKDJurmTk48oYvLBB6g3xiVnQTJKY2zMQC5mgmNCcf9AtjVNNcczgnzCJEO8wqedsuNuWk3y3lQiKOwQhg==",
"path": "microsoft.templateengine.orchestrator.runnableprojects/1.0.1-beta3-20180212-1375715",
"hashPath": "microsoft.templateengine.orchestrator.runnableprojects.1.0.1-beta3-20180212-1375715.nupkg.sha512"
},
"Microsoft.TemplateEngine.Utils/1.0.1-beta3-20180212-1375715": {
"type": "package",
"serviceable": true,
"sha512": "sha512-JSFRHP88D9Jar3O0uI8wMsk6CzS6IZMNvRBgRorZxfywxZ8aY1CFKEYfjGH/Dz2biWwrzcI4YukHWcYnfS4uqA==",
"path": "microsoft.templateengine.utils/1.0.1-beta3-20180212-1375715",
"hashPath": "microsoft.templateengine.utils.1.0.1-beta3-20180212-1375715.nupkg.sha512"
},
"Microsoft.Win32.Primitives/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-9ZQKCWxH7Ijp9BfahvL2Zyf1cJIk8XYLF6Yjzr2yi0b2cOut/HQ31qf1ThHAgCc3WiZMdnWcfJCgN82/0UunxA==",
"path": "microsoft.win32.primitives/4.3.0",
"hashPath": "microsoft.win32.primitives.4.3.0.nupkg.sha512"
},
"Microsoft.Win32.Registry/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-Lw1/VwLH1yxz6SfFEjVRCN0pnflLEsWgnV4qsdJ512/HhTwnKXUG+zDQ4yTO3K/EJQemGoNaBHX5InISNKTzUQ==",
"path": "microsoft.win32.registry/4.3.0",
"hashPath": "microsoft.win32.registry.4.3.0.nupkg.sha512"
},
"Newtonsoft.Json/9.0.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-U82mHQSKaIk+lpSVCbWYKNavmNH1i5xrExDEquU1i6I5pV6UMOqRnJRSlKO3cMPfcpp0RgDY+8jUXHdQ4IfXvw==",
"path": "newtonsoft.json/9.0.1",
"hashPath": "newtonsoft.json.9.0.1.nupkg.sha512"
},
"runtime.native.System/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==",
"path": "runtime.native.system/4.3.0",
"hashPath": "runtime.native.system.4.3.0.nupkg.sha512"
},
"runtime.native.System.IO.Compression/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-INBPonS5QPEgn7naufQFXJEp3zX6L4bwHgJ/ZH78aBTpeNfQMtf7C6VrAFhlq2xxWBveIOWyFzQjJ8XzHMhdOQ==",
"path": "runtime.native.system.io.compression/4.3.0",
"hashPath": "runtime.native.system.io.compression.4.3.0.nupkg.sha512"
},
"System.Buffers/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-ratu44uTIHgeBeI0dE8DWvmXVBSo4u7ozRZZHOMmK/JPpYyo0dAfgSiHlpiObMQ5lEtEyIXA40sKRYg5J6A8uQ==",
"path": "system.buffers/4.3.0",
"hashPath": "system.buffers.4.3.0.nupkg.sha512"
},
"System.Collections/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==",
"path": "system.collections/4.3.0",
"hashPath": "system.collections.4.3.0.nupkg.sha512"
},
"System.Diagnostics.Debug/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==",
"path": "system.diagnostics.debug/4.3.0",
"hashPath": "system.diagnostics.debug.4.3.0.nupkg.sha512"
},
"System.Diagnostics.Process/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-J0wOX07+QASQblsfxmIMFc9Iq7KTXYL3zs2G/Xc704Ylv3NpuVdo6gij6V3PGiptTxqsK0K7CdXenRvKUnkA2g==",
"path": "system.diagnostics.process/4.3.0",
"hashPath": "system.diagnostics.process.4.3.0.nupkg.sha512"
},
"System.Diagnostics.Tools/4.0.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-xBfJ8pnd4C17dWaC9FM6aShzbJcRNMChUMD42I6772KGGrqaFdumwhn9OdM68erj1ueNo3xdQ1EwiFjK5k8p0g==",
"path": "system.diagnostics.tools/4.0.1",
"hashPath": "system.diagnostics.tools.4.0.1.nupkg.sha512"
},
"System.Diagnostics.Tracing/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-rswfv0f/Cqkh78rA5S8eN8Neocz234+emGCtTF3lxPY96F+mmmUen6tbn0glN6PMvlKQb9bPAY5e9u7fgPTkKw==",
"path": "system.diagnostics.tracing/4.3.0",
"hashPath": "system.diagnostics.tracing.4.3.0.nupkg.sha512"
},
"System.Dynamic.Runtime/4.0.11": {
"type": "package",
"serviceable": true,
"sha512": "sha512-db34f6LHYM0U0JpE+sOmjar27BnqTVkbLJhgfwMpTdgTigG/Hna3m2MYVwnFzGGKnEJk2UXFuoVTr8WUbU91/A==",
"path": "system.dynamic.runtime/4.0.11",
"hashPath": "system.dynamic.runtime.4.0.11.nupkg.sha512"
},
"System.Globalization/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==",
"path": "system.globalization/4.3.0",
"hashPath": "system.globalization.4.3.0.nupkg.sha512"
},
"System.IO/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==",
"path": "system.io/4.3.0",
"hashPath": "system.io.4.3.0.nupkg.sha512"
},
"System.IO.Compression/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-YHndyoiV90iu4iKG115ibkhrG+S3jBm8Ap9OwoUAzO5oPDAWcr0SFwQFm0HjM8WkEZWo0zvLTyLmbvTkW1bXgg==",
"path": "system.io.compression/4.3.0",
"hashPath": "system.io.compression.4.3.0.nupkg.sha512"
},
"System.IO.FileSystem/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-3wEMARTnuio+ulnvi+hkRNROYwa1kylvYahhcLk4HSoVdl+xxTFVeVlYOfLwrDPImGls0mDqbMhrza8qnWPTdA==",
"path": "system.io.filesystem/4.3.0",
"hashPath": "system.io.filesystem.4.3.0.nupkg.sha512"
},
"System.IO.FileSystem.Primitives/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-6QOb2XFLch7bEc4lIcJH49nJN2HV+OC3fHDgsLVsBVBk3Y4hFAnOBGzJ2lUu7CyDDFo9IBWkSsnbkT6IBwwiMw==",
"path": "system.io.filesystem.primitives/4.3.0",
"hashPath": "system.io.filesystem.primitives.4.3.0.nupkg.sha512"
},
"System.Linq/4.1.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-bQ0iYFOQI0nuTnt+NQADns6ucV4DUvMdwN6CbkB1yj8i7arTGiTN5eok1kQwdnnNWSDZfIUySQY+J3d5KjWn0g==",
"path": "system.linq/4.1.0",
"hashPath": "system.linq.4.1.0.nupkg.sha512"
},
"System.Linq.Expressions/4.1.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-I+y02iqkgmCAyfbqOmSDOgqdZQ5tTj80Akm5BPSS8EeB0VGWdy6X1KCoYe8Pk6pwDoAKZUOdLVxnTJcExiv5zw==",
"path": "system.linq.expressions/4.1.0",
"hashPath": "system.linq.expressions.4.1.0.nupkg.sha512"
},
"System.ObjectModel/4.0.12": {
"type": "package",
"serviceable": true,
"sha512": "sha512-tAgJM1xt3ytyMoW4qn4wIqgJYm7L7TShRZG4+Q4Qsi2PCcj96pXN7nRywS9KkB3p/xDUjc2HSwP9SROyPYDYKQ==",
"path": "system.objectmodel/4.0.12",
"hashPath": "system.objectmodel.4.0.12.nupkg.sha512"
},
"System.Reflection/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==",
"path": "system.reflection/4.3.0",
"hashPath": "system.reflection.4.3.0.nupkg.sha512"
},
"System.Reflection.Emit/4.0.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-P2wqAj72fFjpP6wb9nSfDqNBMab+2ovzSDzUZK7MVIm54tBJEPr9jWfSjjoTpPwj1LeKcmX3vr0ttyjSSFM47g==",
"path": "system.reflection.emit/4.0.1",
"hashPath": "system.reflection.emit.4.0.1.nupkg.sha512"
},
"System.Reflection.Emit.ILGeneration/4.0.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-Ov6dU8Bu15Bc7zuqttgHF12J5lwSWyTf1S+FJouUXVMSqImLZzYaQ+vRr1rQ0OZ0HqsrwWl4dsKHELckQkVpgA==",
"path": "system.reflection.emit.ilgeneration/4.0.1",
"hashPath": "system.reflection.emit.ilgeneration.4.0.1.nupkg.sha512"
},
"System.Reflection.Emit.Lightweight/4.0.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-sSzHHXueZ5Uh0OLpUQprhr+ZYJrLPA2Cmr4gn0wj9+FftNKXx8RIMKvO9qnjk2ebPYUjZ+F2ulGdPOsvj+MEjA==",
"path": "system.reflection.emit.lightweight/4.0.1",
"hashPath": "system.reflection.emit.lightweight.4.0.1.nupkg.sha512"
},
"System.Reflection.Extensions/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==",
"path": "system.reflection.extensions/4.3.0",
"hashPath": "system.reflection.extensions.4.3.0.nupkg.sha512"
},
"System.Reflection.Primitives/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==",
"path": "system.reflection.primitives/4.3.0",
"hashPath": "system.reflection.primitives.4.3.0.nupkg.sha512"
},
"System.Reflection.TypeExtensions/4.1.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-tsQ/ptQ3H5FYfON8lL4MxRk/8kFyE0A+tGPXmVP967cT/gzLHYxIejIYSxp4JmIeFHVP78g/F2FE1mUUTbDtrg==",
"path": "system.reflection.typeextensions/4.1.0",
"hashPath": "system.reflection.typeextensions.4.1.0.nupkg.sha512"
},
"System.Resources.ResourceManager/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==",
"path": "system.resources.resourcemanager/4.3.0",
"hashPath": "system.resources.resourcemanager.4.3.0.nupkg.sha512"
},
"System.Runtime/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==",
"path": "system.runtime/4.3.0",
"hashPath": "system.runtime.4.3.0.nupkg.sha512"
},
"System.Runtime.Extensions/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==",
"path": "system.runtime.extensions/4.3.0",
"hashPath": "system.runtime.extensions.4.3.0.nupkg.sha512"
},
"System.Runtime.Handles/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==",
"path": "system.runtime.handles/4.3.0",
"hashPath": "system.runtime.handles.4.3.0.nupkg.sha512"
},
"System.Runtime.InteropServices/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==",
"path": "system.runtime.interopservices/4.3.0",
"hashPath": "system.runtime.interopservices.4.3.0.nupkg.sha512"
},
"System.Runtime.InteropServices.RuntimeInformation/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw==",
"path": "system.runtime.interopservices.runtimeinformation/4.3.0",
"hashPath": "system.runtime.interopservices.runtimeinformation.4.3.0.nupkg.sha512"
},
"System.Runtime.Loader/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-DHMaRn8D8YCK2GG2pw+UzNxn/OHVfaWx7OTLBD/hPegHZZgcZh3H6seWegrC4BYwsfuGrywIuT+MQs+rPqRLTQ==",
"path": "system.runtime.loader/4.3.0",
"hashPath": "system.runtime.loader.4.3.0.nupkg.sha512"
},
"System.Runtime.Serialization.Primitives/4.1.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-HZ6Du5QrTG8MNJbf4e4qMO3JRAkIboGT5Fk804uZtg3Gq516S7hAqTm2UZKUHa7/6HUGdVy3AqMQKbns06G/cg==",
"path": "system.runtime.serialization.primitives/4.1.1",
"hashPath": "system.runtime.serialization.primitives.4.1.1.nupkg.sha512"
},
"System.Text.Encoding/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==",
"path": "system.text.encoding/4.3.0",
"hashPath": "system.text.encoding.4.3.0.nupkg.sha512"
},
"System.Text.Encoding.Extensions/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-YVMK0Bt/A43RmwizJoZ22ei2nmrhobgeiYwFzC4YAN+nue8RF6djXDMog0UCn+brerQoYVyaS+ghy9P/MUVcmw==",
"path": "system.text.encoding.extensions/4.3.0",
"hashPath": "system.text.encoding.extensions.4.3.0.nupkg.sha512"
},
"System.Text.RegularExpressions/4.1.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-i88YCXpRTjCnoSQZtdlHkAOx4KNNik4hMy83n0+Ftlb7jvV6ZiZWMpnEZHhjBp6hQVh8gWd/iKNPzlPF7iyA2g==",
"path": "system.text.regularexpressions/4.1.0",
"hashPath": "system.text.regularexpressions.4.1.0.nupkg.sha512"
},
"System.Threading/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==",
"path": "system.threading/4.3.0",
"hashPath": "system.threading.4.3.0.nupkg.sha512"
},
"System.Threading.Tasks/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==",
"path": "system.threading.tasks/4.3.0",
"hashPath": "system.threading.tasks.4.3.0.nupkg.sha512"
},
"System.Threading.Tasks.Extensions/4.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-pH4FZDsZQ/WmgJtN4LWYmRdJAEeVkyriSwrv2Teoe5FOU0Yxlb6II6GL8dBPOfRmutHGATduj3ooMt7dJ2+i+w==",
"path": "system.threading.tasks.extensions/4.0.0",
"hashPath": "system.threading.tasks.extensions.4.0.0.nupkg.sha512"
},
"System.Threading.Thread/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-OHmbT+Zz065NKII/ZHcH9XO1dEuLGI1L2k7uYss+9C1jLxTC9kTZZuzUOyXHayRk+dft9CiDf3I/QZ0t8JKyBQ==",
"path": "system.threading.thread/4.3.0",
"hashPath": "system.threading.thread.4.3.0.nupkg.sha512"
},
"System.Threading.ThreadPool/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-k/+g4b7vjdd4aix83sTgC9VG6oXYKAktSfNIJUNGxPEj7ryEOfzHHhfnmsZvjxawwcD9HyWXKCXmPjX8U4zeSw==",
"path": "system.threading.threadpool/4.3.0",
"hashPath": "system.threading.threadpool.4.3.0.nupkg.sha512"
},
"System.Xml.ReaderWriter/4.0.11": {
"type": "package",
"serviceable": true,
"sha512": "sha512-ZIiLPsf67YZ9zgr31vzrFaYQqxRPX9cVHjtPSnmx4eN6lbS/yEyYNr2vs1doGDEscF0tjCZFsk9yUg1sC9e8tg==",
"path": "system.xml.readerwriter/4.0.11",
"hashPath": "system.xml.readerwriter.4.0.11.nupkg.sha512"
},
"System.Xml.XDocument/4.0.11": {
"type": "package",
"serviceable": true,
"sha512": "sha512-Mk2mKmPi0nWaoiYeotq1dgeNK1fqWh61+EK+w4Wu8SWuTYLzpUnschb59bJtGywaPq7SmTuPf44wrXRwbIrukg==",
"path": "system.xml.xdocument/4.0.11",
"hashPath": "system.xml.xdocument.4.0.11.nupkg.sha512"
}
}
}

Двоичные данные
resources/dotnetJsonCli/Microsoft.TemplateEngine.JsonCli.dll Executable file

Двоичный файл не отображается.

Двоичные данные
resources/dotnetJsonCli/Microsoft.TemplateEngine.JsonCli.pdb Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,9 @@
{
"runtimeOptions": {
"tfm": "netcoreapp2.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "2.0.0"
}
}
}

Двоичный файл не отображается.

Двоичные данные
resources/dotnetJsonCli/Microsoft.TemplateEngine.Utils.dll Executable file

Двоичный файл не отображается.

Двоичные данные
resources/dotnetJsonCli/Newtonsoft.Json.dll Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -10,7 +10,7 @@ import { localSettingsFileName } from './constants';
import { NoSubscriptionError } from './errors';
import { ext } from './extensionVariables';
import { localize } from './localize';
import { getResourceTypeLabel, ResourceType } from './templates/ConfigSetting';
import { getResourceTypeLabel, ResourceType } from './templates/IFunctionSetting';
import * as azUtil from './utils/azure';
import { IResourceResult } from './utils/azure';
import * as fsUtil from './utils/fs';

Просмотреть файл

@ -5,31 +5,28 @@
import * as fse from 'fs-extra';
import * as path from 'path';
import { OutputChannel } from "vscode";
import { IAzureUserInput } from 'vscode-azureextensionui';
// tslint:disable-next-line:no-require-imports
import XRegExp = require('xregexp');
import { ProjectRuntime } from '../../constants';
import { localize } from "../../localize";
import { Template } from "../../templates/Template";
import { removeLanguageFromId } from "../../templates/TemplateData";
import { cpUtils } from "../../utils/cpUtils";
import { executeDotnetTemplateCommand } from '../../templates/executeDotnetTemplateCommand';
import { IFunctionTemplate } from "../../templates/IFunctionTemplate";
import { dotnetUtils } from '../../utils/dotnetUtils';
import * as fsUtil from '../../utils/fs';
import { FunctionCreatorBase } from './FunctionCreatorBase';
export class CSharpFunctionCreator extends FunctionCreatorBase {
private _outputChannel: OutputChannel;
private _functionName: string;
private _namespace: string;
constructor(functionAppPath: string, template: Template, outputChannel: OutputChannel) {
constructor(functionAppPath: string, template: IFunctionTemplate) {
super(functionAppPath, template);
this._outputChannel = outputChannel;
}
public async promptForSettings(ui: IAzureUserInput, functionName: string | undefined, functionSettings: { [key: string]: string | undefined; }): Promise<void> {
if (!functionName) {
const defaultFunctionName: string | undefined = await fsUtil.getUniqueFsPath(this._functionAppPath, removeLanguageFromId(this._template.id), '.cs');
const defaultFunctionName: string | undefined = await fsUtil.getUniqueFsPath(this._functionAppPath, this._template.defaultFunctionName, '.cs');
this._functionName = await ui.showInputBox({
placeHolder: localize('azFunc.funcNamePlaceholder', 'Function name'),
prompt: localize('azFunc.funcNamePrompt', 'Provide a function name'),
@ -52,36 +49,22 @@ export class CSharpFunctionCreator extends FunctionCreatorBase {
}
}
public async createFunction(userSettings: { [propertyName: string]: string }): Promise<string | undefined> {
await dotnetUtils.validateTemplatesInstalled();
public async createFunction(userSettings: { [propertyName: string]: string }, runtime: ProjectRuntime): Promise<string | undefined> {
await dotnetUtils.validateDotnetInstalled();
const args: string[] = [];
args.push('--arg:name');
args.push(this._functionName);
args.push('--arg:namespace');
args.push(this._namespace);
for (const key of Object.keys(userSettings)) {
let parameter: string = key.charAt(0).toUpperCase() + key.slice(1);
// the parameters for dotnet templates are not consistent. Hence, we have to special-case a few of them:
if (parameter.toLowerCase() === 'authlevel') {
parameter = 'AccessRights';
}
// https://github.com/Microsoft/vscode-azurefunctions/issues/166
const nameSuffix: string = '/{name}';
if (userSettings[key].endsWith(nameSuffix)) {
userSettings[key] = userSettings[key].slice(0, -1 * nameSuffix.length);
}
args.push(`--${parameter}="${userSettings[key]}"`);
args.push(`--arg:${key}`);
args.push(`"${userSettings[key]}"`);
}
await cpUtils.executeCommand(
this._outputChannel,
this._functionAppPath,
'dotnet',
'new',
removeLanguageFromId(this._template.id),
`--name="${this._functionName}"`,
`--namespace="${this._namespace}"`,
...args
);
await executeDotnetTemplateCommand(runtime, this._functionAppPath, 'create', '--identity', this._template.id, ...args);
return path.join(this._functionAppPath, `${this._functionName}.cs`);
}

Просмотреть файл

@ -4,14 +4,15 @@
*--------------------------------------------------------------------------------------------*/
import { IAzureUserInput } from "vscode-azureextensionui";
import { Template } from "../../templates/Template";
import { ProjectRuntime } from "../../constants";
import { IFunctionTemplate } from "../../templates/IFunctionTemplate";
export abstract class FunctionCreatorBase {
protected readonly _functionNameRegex: RegExp = /^[a-zA-Z][a-zA-Z\d_\-]*$/;
protected _functionAppPath: string;
protected _template: Template;
protected _template: IFunctionTemplate;
constructor(functionAppPath: string, template: Template) {
constructor(functionAppPath: string, template: IFunctionTemplate) {
this._functionAppPath = functionAppPath;
this._template = template;
}
@ -21,5 +22,5 @@ export abstract class FunctionCreatorBase {
* This includes the function name (Since the name could have different restrictions for different languages)
*/
public abstract async promptForSettings(ui: IAzureUserInput, functionName: string | undefined, functionSettings: { [key: string]: string | undefined; }): Promise<void>;
public abstract async createFunction(userSettings: { [propertyName: string]: string }): Promise<string | undefined>;
public abstract async createFunction(userSettings: { [propertyName: string]: string }, runtime: ProjectRuntime): Promise<string | undefined>;
}

Просмотреть файл

@ -8,8 +8,8 @@ import * as path from 'path';
import { OutputChannel } from "vscode";
import { IAzureUserInput } from 'vscode-azureextensionui';
import { localize } from "../../localize";
import { Template } from "../../templates/Template";
import { removeLanguageFromId } from "../../templates/TemplateData";
import { removeLanguageFromId } from "../../templates/FunctionTemplates";
import { IFunctionTemplate } from "../../templates/IFunctionTemplate";
import { cpUtils } from "../../utils/cpUtils";
import * as fsUtil from '../../utils/fs';
import { getFullClassName, parseJavaClassName, validatePackageName } from "../../utils/javaNameUtils";
@ -25,7 +25,7 @@ export class JavaFunctionCreator extends FunctionCreatorBase {
private _packageName: string;
private _functionName: string;
constructor(functionAppPath: string, template: Template, outputChannel: OutputChannel) {
constructor(functionAppPath: string, template: IFunctionTemplate, outputChannel: OutputChannel) {
super(functionAppPath, template);
this._outputChannel = outputChannel;
}

Просмотреть файл

@ -8,7 +8,7 @@ import * as path from 'path';
import { IAzureUserInput } from 'vscode-azureextensionui';
import { ProjectLanguage } from '../../constants';
import { localize } from "../../localize";
import { Template } from "../../templates/Template";
import { IScriptFunctionTemplate } from '../../templates/parseScriptTemplates';
import * as fsUtil from '../../utils/fs';
import { FunctionCreatorBase } from './FunctionCreatorBase';
@ -41,10 +41,11 @@ export function getScriptFileNameFromLanguage(language: string): string | undefi
* Function creator for multiple languages that don't require compilation (JavaScript, C# Script, Bash, etc.)
*/
export class ScriptFunctionCreator extends FunctionCreatorBase {
protected _template: IScriptFunctionTemplate;
private _language: string;
private _functionName: string;
constructor(functionAppPath: string, template: Template, language: string) {
constructor(functionAppPath: string, template: IScriptFunctionTemplate, language: string) {
super(functionAppPath, template);
this._language = language;
}

Просмотреть файл

@ -14,9 +14,9 @@ import { ext } from '../../extensionVariables';
import { promptForAppSetting, validateAzureWebJobsStorage } from '../../LocalAppSettings';
import { localize } from '../../localize';
import { getProjectLanguage, getProjectRuntime, getTemplateFilter, promptForProjectLanguage, promptForProjectRuntime, selectTemplateFilter, updateWorkspaceSetting } from '../../ProjectSettings';
import { ConfigSetting, ValueType } from '../../templates/ConfigSetting';
import { EnumValue } from '../../templates/EnumValue';
import { Template } from '../../templates/Template';
import { IEnumValue, IFunctionSetting, ValueType } from '../../templates/IFunctionSetting';
import { IFunctionTemplate } from '../../templates/IFunctionTemplate';
import { IScriptFunctionTemplate } from '../../templates/parseScriptTemplates';
import * as workspaceUtil from '../../utils/workspace';
import { createNewProject } from '../createNewProject/createNewProject';
import { isFunctionProject } from '../createNewProject/validateFunctionProjects';
@ -25,7 +25,7 @@ import { FunctionCreatorBase } from './FunctionCreatorBase';
import { JavaFunctionCreator } from './JavaFunctionCreator';
import { ScriptFunctionCreator } from './ScriptFunctionCreator';
async function promptForSetting(actionContext: IActionContext, localSettingsPath: string, setting: ConfigSetting, defaultValue?: string): Promise<string> {
async function promptForSetting(actionContext: IActionContext, localSettingsPath: string, setting: IFunctionSetting): Promise<string> {
if (setting.resourceType !== undefined) {
return await promptForAppSetting(actionContext, localSettingsPath, setting.resourceType);
} else {
@ -36,18 +36,18 @@ async function promptForSetting(actionContext: IActionContext, localSettingsPath
return await promptForEnumSetting(setting);
default:
// Default to 'string' type for any setting that isn't supported
return await promptForStringSetting(setting, defaultValue);
return await promptForStringSetting(setting);
}
}
}
async function promptForEnumSetting(setting: ConfigSetting): Promise<string> {
const picks: IAzureQuickPickItem<string>[] = setting.enums.map((ev: EnumValue) => { return { data: ev.value, label: ev.displayName, description: '' }; });
async function promptForEnumSetting(setting: IFunctionSetting): Promise<string> {
const picks: IAzureQuickPickItem<string>[] = setting.enums.map((ev: IEnumValue) => { return { data: ev.value, label: ev.displayName, description: '' }; });
return (await ext.ui.showQuickPick(picks, { placeHolder: setting.label })).data;
}
async function promptForBooleanSetting(setting: ConfigSetting): Promise<string> {
async function promptForBooleanSetting(setting: IFunctionSetting): Promise<string> {
const picks: QuickPickItem[] = [
{ label: 'true', description: '' },
{ label: 'false', description: '' }
@ -56,12 +56,12 @@ async function promptForBooleanSetting(setting: ConfigSetting): Promise<string>
return (await ext.ui.showQuickPick(picks, { placeHolder: setting.label })).label;
}
async function promptForStringSetting(setting: ConfigSetting, defaultValue?: string): Promise<string> {
async function promptForStringSetting(setting: IFunctionSetting): Promise<string> {
const options: vscode.InputBoxOptions = {
placeHolder: setting.label,
prompt: localize('azFunc.stringSettingPrompt', 'Provide a \'{0}\'', setting.label),
validateInput: (s: string): string | undefined => setting.validateSetting(s),
value: defaultValue ? defaultValue : setting.defaultValue
value: setting.defaultValue
};
return await ext.ui.showInputBox(options);
}
@ -111,14 +111,14 @@ export async function createFunction(
runtime = await getProjectRuntime(language, functionAppPath, ext.ui);
}
let template: Template;
let template: IFunctionTemplate;
if (!templateId) {
templateFilter = await getTemplateFilter(functionAppPath);
[template, language, runtime, templateFilter] = await promptForTemplate(functionAppPath, language, runtime, templateFilter);
} else {
templateFilter = TemplateFilter.All;
const templates: Template[] = await ext.templateData.getTemplates(language, runtime, TemplateFilter.All);
const foundTemplate: Template | undefined = templates.find((t: Template) => t.id === templateId);
const templates: IFunctionTemplate[] = await ext.functionTemplates.getTemplates(language, runtime, TemplateFilter.All);
const foundTemplate: IFunctionTemplate | undefined = templates.find((t: IFunctionTemplate) => t.id === templateId);
if (foundTemplate) {
template = foundTemplate;
} else {
@ -138,38 +138,34 @@ export async function createFunction(
functionCreator = new JavaFunctionCreator(functionAppPath, template, ext.outputChannel);
break;
case ProjectLanguage.CSharp:
functionCreator = new CSharpFunctionCreator(functionAppPath, template, ext.outputChannel);
functionCreator = new CSharpFunctionCreator(functionAppPath, template);
break;
default:
functionCreator = new ScriptFunctionCreator(functionAppPath, template, language);
functionCreator = new ScriptFunctionCreator(functionAppPath, <IScriptFunctionTemplate>template, language);
break;
}
await functionCreator.promptForSettings(ext.ui, functionName, functionSettings);
const userSettings: { [propertyName: string]: string } = {};
for (const settingName of template.userPromptedSettings) {
const setting: ConfigSetting | undefined = await ext.templateData.getSetting(runtime, template.functionConfig.inBindingType, settingName);
if (setting) {
let settingValue: string | undefined;
if (functionSettings[settingName.toLowerCase()] !== undefined) {
settingValue = functionSettings[settingName.toLowerCase()];
} else {
const defaultValue: string | undefined = template.functionConfig.inBinding[settingName];
settingValue = await promptForSetting(actionContext, localSettingsPath, setting, defaultValue);
}
userSettings[settingName] = settingValue ? settingValue : '';
for (const setting of template.userPromptedSettings) {
let settingValue: string | undefined;
if (functionSettings[setting.name.toLowerCase()] !== undefined) {
settingValue = functionSettings[setting.name.toLowerCase()];
} else {
settingValue = await promptForSetting(actionContext, localSettingsPath, setting);
}
userSettings[setting.name] = settingValue ? settingValue : '';
}
const newFilePath: string | undefined = await functionCreator.createFunction(userSettings);
const newFilePath: string | undefined = await functionCreator.createFunction(userSettings, runtime);
if (newFilePath && (await fse.pathExists(newFilePath))) {
const newFileUri: vscode.Uri = vscode.Uri.file(newFilePath);
vscode.window.showTextDocument(await vscode.workspace.openTextDocument(newFileUri));
}
if (!template.functionConfig.isHttpTrigger) {
if (!template.isHttpTrigger) {
await validateAzureWebJobsStorage(actionContext, localSettingsPath);
}
@ -178,15 +174,15 @@ export async function createFunction(
}
}
async function promptForTemplate(functionAppPath: string, language: ProjectLanguage, runtime: ProjectRuntime, templateFilter: TemplateFilter): Promise<[Template, ProjectLanguage, ProjectRuntime, TemplateFilter]> {
async function promptForTemplate(functionAppPath: string, language: ProjectLanguage, runtime: ProjectRuntime, templateFilter: TemplateFilter): Promise<[IFunctionTemplate, ProjectLanguage, ProjectRuntime, TemplateFilter]> {
const runtimePickId: string = 'runtime';
const languagePickId: string = 'language';
const filterPickId: string = 'filter';
let template: Template | undefined;
let template: IFunctionTemplate | undefined;
while (!template) {
const templates: Template[] = await ext.templateData.getTemplates(language, runtime, templateFilter);
let picks: IAzureQuickPickItem<Template | string>[] = templates.map((t: Template) => { return { data: t, label: t.name, description: '' }; });
const templates: IFunctionTemplate[] = await ext.functionTemplates.getTemplates(language, runtime, templateFilter);
let picks: IAzureQuickPickItem<IFunctionTemplate | string>[] = templates.map((t: IFunctionTemplate) => { return { data: t, label: t.name, description: '' }; });
picks = picks.concat([
{ label: localize('selectRuntime', '$(gear) Change project runtime'), description: localize('currentRuntime', 'Current: {0}', runtime), data: runtimePickId, suppressPersistence: true },
{ label: localize('selectLanguage', '$(gear) Change project language'), description: localize('currentLanguage', 'Current: {0}', language), data: languagePickId, suppressPersistence: true },
@ -194,7 +190,7 @@ async function promptForTemplate(functionAppPath: string, language: ProjectLangu
]);
const placeHolder: string = templates.length > 0 ? localize('azFunc.selectFuncTemplate', 'Select a function template') : localize('azFunc.noTemplatesFound', 'No templates found. Change your settings to view more templates');
const result: Template | string = (await ext.ui.showQuickPick(picks, { placeHolder })).data;
const result: IFunctionTemplate | string = (await ext.ui.showQuickPick(picks, { placeHolder })).data;
if (isString(result)) {
switch (result) {
case runtimePickId:

Просмотреть файл

@ -11,9 +11,10 @@ import { SemVer } from 'semver';
import * as vscode from 'vscode';
import { DialogResponses, parseError } from 'vscode-azureextensionui';
import { gitignoreFileName, hostFileName, isWindows, localSettingsFileName, ProjectRuntime, TemplateFilter } from '../../constants';
import { tryGetLocalRuntimeVersion } from '../../funcCoreTools/tryGetLocalRuntimeVersion';
import { localize } from "../../localize";
import { getFuncExtensionSetting, updateGlobalSetting } from '../../ProjectSettings';
import { cpUtils } from '../../utils/cpUtils';
import { getFuncExtensionSetting, promptForProjectRuntime, updateGlobalSetting } from '../../ProjectSettings';
import { executeDotnetTemplateCommand } from '../../templates/executeDotnetTemplateCommand';
import { dotnetUtils } from '../../utils/dotnetUtils';
import { funcHostTaskId, ProjectCreatorBase } from './IProjectCreator';
@ -25,18 +26,16 @@ export class CSharpProjectCreator extends ProjectCreatorBase {
private _runtime: ProjectRuntime;
public async addNonVSCodeFiles(): Promise<void> {
await dotnetUtils.validateTemplatesInstalled();
await dotnetUtils.validateDotnetInstalled();
const csProjName: string = `${path.basename(this.functionAppPath)}.csproj`;
const overwriteExisting: boolean = await this.confirmOverwriteExisting(this.functionAppPath, csProjName);
await cpUtils.executeCommand(
this.outputChannel,
this.functionAppPath,
'dotnet',
'new',
dotnetUtils.funcProjectId,
overwriteExisting ? '--force' : ''
);
const projectName: string = path.basename(this.functionAppPath);
const csProjName: string = `${projectName}.csproj`;
await this.confirmOverwriteExisting(this.functionAppPath, csProjName);
// tslint:disable-next-line:strict-boolean-expressions
this._runtime = await tryGetLocalRuntimeVersion() || await promptForProjectRuntime(this.ui);
const identity: string = `Microsoft.AzureFunctions.ProjectTemplate.CSharp.${this._runtime === ProjectRuntime.one ? '1' : '2'}.x`;
await executeDotnetTemplateCommand(this._runtime, this.functionAppPath, 'create', '--identity', identity, '--arg:name', projectName);
}
public async getRuntime(): Promise<ProjectRuntime> {

Просмотреть файл

@ -19,6 +19,7 @@ export enum ProjectLanguage {
Batch = 'Batch',
CSharp = 'C#',
CSharpScript = 'C#Script',
FSharp = 'F#',
FSharpScript = 'F#Script',
Java = 'Java',
JavaScript = 'JavaScript',

Просмотреть файл

@ -38,12 +38,11 @@ import { stopFunctionApp } from './commands/stopFunctionApp';
import { ext } from './extensionVariables';
import { uninstallFuncCoreTools } from './funcCoreTools/uninstallFuncCoreTools';
import { validateFuncCoreToolsIsLatest } from './funcCoreTools/validateFuncCoreToolsIsLatest';
import { getTemplateData } from './templates/TemplateData';
import { FunctionTemplates, getFunctionTemplates } from './templates/FunctionTemplates';
import { FunctionAppProvider } from './tree/FunctionAppProvider';
import { FunctionAppTreeItem } from './tree/FunctionAppTreeItem';
import { FunctionTreeItem } from './tree/FunctionTreeItem';
import { ProxyTreeItem } from './tree/ProxyTreeItem';
import { dotnetUtils } from './utils/dotnetUtils';
export function activate(context: vscode.ExtensionContext): void {
registerUIExtensionVariables(ext);
@ -85,7 +84,9 @@ export function activate(context: vscode.ExtensionContext): void {
await validateFunctionProjects(this, ui, outputChannel, event.added);
});
const templateDataTask: Promise<void> = getTemplateDataTask(context);
const templatesTask: Promise<void> = getFunctionTemplates().then((templates: FunctionTemplates) => {
ext.functionTemplates = templates;
});
registerCommand('azureFunctions.selectSubscriptions', () => vscode.commands.executeCommand('azure-account.selectSubscriptions'));
registerCommand('azureFunctions.refresh', async (node?: IAzureNode) => await tree.refresh(node));
@ -93,11 +94,11 @@ export function activate(context: vscode.ExtensionContext): void {
registerCommand('azureFunctions.loadMore', async (node: IAzureNode) => await tree.loadMore(node));
registerCommand('azureFunctions.openInPortal', async (node?: IAzureNode<FunctionAppTreeItem>) => await openInPortal(tree, node));
registerCommand('azureFunctions.createFunction', async function (this: IActionContext, functionAppPath?: string, templateId?: string, functionName?: string, functionSettings?: {}): Promise<void> {
await templateDataTask;
await templatesTask;
await createFunction(this, functionAppPath, templateId, functionName, functionSettings);
});
registerCommand('azureFunctions.createNewProject', async function (this: IActionContext, functionAppPath?: string, language?: string, runtime?: string, openFolder?: boolean | undefined, templateId?: string, functionName?: string, functionSettings?: {}): Promise<void> {
await templateDataTask;
await templatesTask;
await createNewProject(this, functionAppPath, language, runtime, openFolder, templateId, functionName, functionSettings);
});
registerCommand('azureFunctions.initProjectForVSCode', async function (this: IActionContext): Promise<void> { await initProjectForVSCode(this.properties, ui, outputChannel); });
@ -120,17 +121,12 @@ export function activate(context: vscode.ExtensionContext): void {
registerCommand('azureFunctions.appSettings.decrypt', async (uri?: vscode.Uri) => await decryptLocalSettings(uri));
registerCommand('azureFunctions.appSettings.encrypt', async (uri?: vscode.Uri) => await encryptLocalSettings(uri));
registerCommand('azureFunctions.appSettings.delete', async (node?: IAzureNode<AppSettingTreeItem>) => await deleteNode(tree, AppSettingTreeItem.contextValue, node));
registerCommand('azureFunctions.uninstallDotnetTemplates', async () => await dotnetUtils.uninstallTemplates());
registerCommand('azureFunctions.debugFunctionAppOnAzure', async (node?: IAzureNode<FunctionAppTreeItem>) => await remoteDebugFunctionApp(outputChannel, ui, tree, node));
registerCommand('azureFunctions.deleteProxy', async (node?: IAzureNode) => await deleteNode(tree, ProxyTreeItem.contextValue, node));
registerCommand('azureFunctions.uninstallFuncCoreTools', async () => await uninstallFuncCoreTools());
});
}
async function getTemplateDataTask(context: vscode.ExtensionContext): Promise<void> {
ext.templateData = await getTemplateData(context.globalState);
}
// tslint:disable-next-line:no-empty
export function deactivate(): void {
}

Просмотреть файл

@ -6,7 +6,7 @@
import { ExtensionContext, OutputChannel } from "vscode";
import { AzureTreeDataProvider, IAzureUserInput } from "vscode-azureextensionui";
import TelemetryReporter from "vscode-extension-telemetry";
import { TemplateData } from "./templates/TemplateData";
import { FunctionTemplates } from "./templates/FunctionTemplates";
/**
* Namespace for common variables used throughout the extension. They must be initialized in the activate() method of extension.ts
@ -16,6 +16,6 @@ export namespace ext {
export let tree: AzureTreeDataProvider;
export let outputChannel: OutputChannel;
export let ui: IAzureUserInput;
export let templateData: TemplateData;
export let functionTemplates: FunctionTemplates;
export let reporter: TelemetryReporter;
}

Просмотреть файл

@ -12,12 +12,12 @@ import * as vscode from 'vscode';
import { callWithTelemetryAndErrorHandling, DialogResponses, IActionContext, parseError } from 'vscode-azureextensionui';
import { PackageManager, ProjectRuntime } from '../constants';
import { ext } from '../extensionVariables';
import { getFuncPackageManager } from '../funcCoreTools/getFuncPackageManager';
import { getLocalFuncCoreToolsVersion } from '../funcCoreTools/getLocalFuncCoreToolsVersion';
import { getProjectRuntimeFromVersion } from '../funcCoreTools/tryGetLocalRuntimeVersion';
import { updateFuncCoreTools } from '../funcCoreTools/updateFuncCoreTools';
import { localize } from '../localize';
import { getFuncExtensionSetting, updateGlobalSetting } from '../ProjectSettings';
import { getFuncPackageManager } from './getFuncPackageManager';
import { getLocalFuncCoreToolsVersion } from './getLocalFuncCoreToolsVersion';
import { getProjectRuntimeFromVersion } from './tryGetLocalRuntimeVersion';
import { updateFuncCoreTools } from './updateFuncCoreTools';
export async function validateFuncCoreToolsIsLatest(): Promise<void> {
await callWithTelemetryAndErrorHandling('azureFunctions.validateFuncCoreToolsIsLatest', async function (this: IActionContext): Promise<void> {

Просмотреть файл

@ -1,22 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ConfigBinding } from './ConfigBinding';
import { ConfigVariables } from './ConfigVariables';
import { Resources } from './Resources';
interface IConfig {
variables: { [name: string]: string };
bindings: object[];
}
export class Config {
public bindings: ConfigBinding[];
constructor(data: object, resources: Resources) {
const config: IConfig = <IConfig>data;
const variables: ConfigVariables = new ConfigVariables(config.variables, resources);
this.bindings = config.bindings.map((b: object) => new ConfigBinding(variables, b));
}
}

Просмотреть файл

@ -1,23 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ConfigSetting } from './ConfigSetting';
import { ConfigVariables } from './ConfigVariables';
interface IBinding {
// tslint:disable-next-line:no-reserved-keywords
type: string;
settings: object[];
}
export class ConfigBinding {
public bindingType: string;
public settings: ConfigSetting[];
constructor(variables: ConfigVariables, data: object) {
const binding: IBinding = <IBinding>data;
this.bindingType = binding.type;
this.settings = binding.settings.map((s: object) => new ConfigSetting(variables, s));
}
}

Просмотреть файл

@ -1,94 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from '../localize';
import { ConfigValidator } from './ConfigValidator';
import { ConfigVariables } from './ConfigVariables';
import { EnumValue } from './EnumValue';
export enum ValueType {
string = 'string',
boolean = 'boolean',
enum = 'enum',
checkBoxList = 'checkBoxList',
int = 'int'
}
export enum ResourceType {
DocumentDB = 'DocumentDB',
Storage = 'Storage',
EventHub = 'EventHub'
}
export function getResourceTypeLabel(resourceType: ResourceType): string {
switch (resourceType) {
case ResourceType.DocumentDB:
return localize('azFunc.DocumentDB', 'Cosmos DB Account');
case ResourceType.Storage:
return localize('azFunc.Storage', 'Storage Account');
case ResourceType.EventHub:
return localize('azFunc.EventHub', 'Event Hub');
default:
return resourceType;
}
}
interface IBindingSetting {
name: string;
value: ValueType;
label: string;
defaultValue?: string;
required: boolean;
resource?: ResourceType;
validators?: object[];
// tslint:disable-next-line:no-reserved-keywords
enum?: object[];
}
export class ConfigSetting {
private _setting: IBindingSetting;
private _variables: ConfigVariables;
constructor(variables: ConfigVariables, data: object) {
this._variables = variables;
this._setting = <IBindingSetting>data;
}
public get resourceType(): ResourceType | undefined {
return this._setting.resource;
}
public get valueType(): ValueType | undefined {
return this._setting.value;
}
public get defaultValue(): string | undefined {
return this._setting.defaultValue ? this._variables.getValue(this._setting.defaultValue) : undefined;
}
public get label(): string {
return this._variables.getValue(this._setting.label);
}
public get name(): string {
return this._variables.getValue(this._setting.name);
}
public get enums(): EnumValue[] {
return this._setting.enum ? this._setting.enum.map((ev: object) => new EnumValue(this._variables, ev)) : [];
}
public validateSetting(value: string | undefined): string | undefined {
if (this._setting.validators) {
const validators: ConfigValidator[] = this._setting.validators.map((v: object) => new ConfigValidator(this._variables, v));
for (const validator of validators) {
if (!value || value.match(validator.expression) === null) {
return validator.errorText;
}
}
}
return undefined;
}
}

Просмотреть файл

@ -1,28 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ConfigVariables } from './ConfigVariables';
interface IConfigValidator {
expression: string;
errorText: string;
}
export class ConfigValidator {
private _validator: IConfigValidator;
private _variables: ConfigVariables;
constructor(variables: ConfigVariables, data: object) {
this._variables = variables;
this._validator = <IConfigValidator>data;
}
public get expression(): string {
return this._validator.expression;
}
public get errorText(): string | undefined {
return this._variables.getValue(this._validator.errorText);
}
}

Просмотреть файл

@ -1,22 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Resources } from './Resources';
export class ConfigVariables {
private _variables: { [name: string]: string };
private _resources: Resources;
constructor(variables: { [name: string]: string }, resources: Resources) {
this._variables = variables;
this._resources = resources;
}
public getValue(data: string): string {
const matches: RegExpMatchArray | null = data.match(/\[variables\(\'(.*)\'\)\]/);
data = matches !== null ? this._variables[matches[1]] : data;
return this._resources.getValue(data);
}
}

Просмотреть файл

@ -0,0 +1,70 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ProjectRuntime } from '../constants';
import { ext } from '../extensionVariables';
import { dotnetUtils } from '../utils/dotnetUtils';
import { downloadFile } from '../utils/fs';
import { cliFeedJsonResponse } from '../utils/getCliFeedJson';
import { executeDotnetTemplateCommand, getDotnetItemTemplatePath, getDotnetProjectTemplatePath } from './executeDotnetTemplateCommand';
import { IFunctionTemplate } from './IFunctionTemplate';
import { parseDotnetTemplates } from './parseDotnetTemplates';
import { TemplateRetriever, TemplateType } from './TemplateRetriever';
export class DotnetTemplateRetriever extends TemplateRetriever {
public templateType: TemplateType = TemplateType.Dotnet;
private _dotnetTemplatesKey: string = 'DotnetTemplates';
private _rawTemplates: object[];
public getVerifiedTemplateIds(runtime: ProjectRuntime): string[] {
return getDotnetVerifiedTemplateIds(runtime);
}
protected async getTemplatesFromCache(runtime: ProjectRuntime): Promise<IFunctionTemplate[] | undefined> {
const cachedDotnetTemplates: object[] | undefined = ext.context.globalState.get<object[]>(this.getCacheKey(this._dotnetTemplatesKey, runtime));
if (cachedDotnetTemplates) {
return parseDotnetTemplates(cachedDotnetTemplates, runtime);
} else {
return undefined;
}
}
protected async getTemplatesFromCliFeed(cliFeedJson: cliFeedJsonResponse, templateVersion: string, runtime: ProjectRuntime): Promise<IFunctionTemplate[]> {
await dotnetUtils.validateDotnetInstalled();
const projectFilePath: string = getDotnetProjectTemplatePath(runtime);
await downloadFile(cliFeedJson.releases[templateVersion].projectTemplates, projectFilePath);
const itemFilePath: string = getDotnetItemTemplatePath(runtime);
await downloadFile(cliFeedJson.releases[templateVersion].itemTemplates, itemFilePath);
this._rawTemplates = <object[]>JSON.parse(await executeDotnetTemplateCommand(runtime, undefined, 'list'));
return parseDotnetTemplates(this._rawTemplates, runtime);
}
protected async cacheTemplatesFromCliFeed(runtime: ProjectRuntime): Promise<void> {
ext.context.globalState.update(this.getCacheKey(this._dotnetTemplatesKey, runtime), this._rawTemplates);
}
}
export function getDotnetVerifiedTemplateIds(runtime: string): string[] {
const verifiedTemplateIds: string[] = [
'Azure.Function.CSharp.HttpTrigger',
'Azure.Function.CSharp.BlobTrigger',
'Azure.Function.CSharp.QueueTrigger',
'Azure.Function.CSharp.TimerTrigger'
];
return verifiedTemplateIds.map((id: string) => {
switch (runtime) {
case ProjectRuntime.one:
return `${id}.1.x`;
case ProjectRuntime.beta:
return `${id}.2.x`;
default:
throw new RangeError();
}
});
}

Просмотреть файл

@ -1,28 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ConfigVariables } from './ConfigVariables';
interface IEnumValue {
value: string;
display: string;
}
export class EnumValue {
private _enumValue: IEnumValue;
private _variables: ConfigVariables;
constructor(variables: ConfigVariables, data: object) {
this._variables = variables;
this._enumValue = <IEnumValue>data;
}
get value(): string {
return this._variables.getValue(this._enumValue.value);
}
get displayName(): string {
return this._variables.getValue(this._enumValue.display);
}
}

Просмотреть файл

@ -0,0 +1,168 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { callWithTelemetryAndErrorHandling, IActionContext, parseError } from 'vscode-azureextensionui';
import { betaReleaseVersion, ProjectLanguage, ProjectRuntime, TemplateFilter, templateVersionSetting, v1ReleaseVersion } from '../constants';
import { ext } from '../extensionVariables';
import { localize } from '../localize';
import { getFuncExtensionSetting, updateGlobalSetting } from '../ProjectSettings';
import { cliFeedJsonResponse, getFeedRuntime, tryGetCliFeedJson } from '../utils/getCliFeedJson';
import { DotnetTemplateRetriever, getDotnetVerifiedTemplateIds } from './DotnetTemplateRetriever';
import { IFunctionTemplate, TemplateCategory } from './IFunctionTemplate';
import { getScriptVerifiedTemplateIds, ScriptTemplateRetriever } from './ScriptTemplateRetriever';
import { TemplateRetriever } from './TemplateRetriever';
const verifiedJavaTemplates: string[] = [
'HttpTrigger',
'BlobTrigger',
'QueueTrigger',
'TimerTrigger'
];
export class FunctionTemplates {
private readonly _templatesMap: { [runtime: string]: IFunctionTemplate[] | undefined } = {};
// if there are no templates, then there is likely no internet or a problem with the clifeed url
private readonly _noInternetErrMsg: string = localize('retryInternet', 'There was an error in retrieving the templates. Recheck your internet connection and try again.');
constructor(templatesMap: { [runtime: string]: IFunctionTemplate[] | undefined }) {
this._templatesMap = templatesMap;
}
public async getTemplates(language: string, runtime: string = ProjectRuntime.one, templateFilter?: string): Promise<IFunctionTemplate[]> {
const templates: IFunctionTemplate[] | undefined = this._templatesMap[runtime];
if (!templates) {
throw new Error(this._noInternetErrMsg);
}
if (language === ProjectLanguage.Java) {
// Currently we leverage JS templates to get the function metadata of Java Functions.
// Will refactor the code here when templates HTTP API is ready.
// See issue here: https://github.com/Microsoft/vscode-azurefunctions/issues/84
const javaTemplates: IFunctionTemplate[] = templates.filter((t: IFunctionTemplate) => t.language === ProjectLanguage.JavaScript);
return javaTemplates.filter((t: IFunctionTemplate) => verifiedJavaTemplates.find((vt: string) => vt === removeLanguageFromId(t.id)));
} else {
let filterTemplates: IFunctionTemplate[] = templates.filter((t: IFunctionTemplate) => t.language.toLowerCase() === language.toLowerCase());
switch (templateFilter) {
case TemplateFilter.All:
break;
case TemplateFilter.Core:
filterTemplates = filterTemplates.filter((t: IFunctionTemplate) => t.categories.find((c: TemplateCategory) => c === TemplateCategory.Core) !== undefined);
break;
case TemplateFilter.Verified:
default:
const verifiedTemplateIds: string[] = getScriptVerifiedTemplateIds(runtime).concat(getDotnetVerifiedTemplateIds(runtime));
filterTemplates = filterTemplates.filter((t: IFunctionTemplate) => verifiedTemplateIds.find((vt: string) => vt === t.id));
}
return filterTemplates;
}
}
}
export async function getFunctionTemplates(): Promise<FunctionTemplates> {
const templatesMap: { [runtime: string]: IFunctionTemplate[] | undefined } = {};
const cliFeedJson: cliFeedJsonResponse | undefined = await tryGetCliFeedJson();
const templateRetrievers: TemplateRetriever[] = [new ScriptTemplateRetriever(), new DotnetTemplateRetriever()];
for (const templateRetriever of templateRetrievers) {
for (const key of Object.keys(ProjectRuntime)) {
const runtime: ProjectRuntime = <ProjectRuntime>ProjectRuntime[key];
await callWithTelemetryAndErrorHandling('azureFunctions.getFunctionTemplates', async function (this: IActionContext): Promise<void> {
this.suppressErrorDisplay = true;
this.properties.isActivationEvent = 'true';
this.properties.runtime = runtime;
this.properties.templateType = templateRetriever.templateType;
const templateVersion: string | undefined = await tryGetTemplateVersionSetting(this, cliFeedJson, runtime);
let templates: IFunctionTemplate[] | undefined;
// 1. Use the cached templates if they match templateVersion
if (ext.context.globalState.get(templateRetriever.getCacheKey(TemplateRetriever.templateVersionKey, runtime)) === templateVersion) {
templates = await templateRetriever.tryGetTemplatesFromCache(this, runtime);
this.properties.templateSource = 'matchingCache';
}
// 2. Download templates from the cli-feed if the cache doesn't match templateVersion
if (!templates && cliFeedJson && templateVersion) {
templates = await templateRetriever.tryGetTemplatesFromCliFeed(this, cliFeedJson, templateVersion, runtime);
this.properties.templateSource = 'cliFeed';
}
// 3. Use the cached templates, even if they don't match templateVersion
if (!templates) {
templates = await templateRetriever.tryGetTemplatesFromCache(this, runtime);
this.properties.templateSource = 'mismatchCache';
}
// 4. Download templates from the cli-feed using the backupVersion
if (!templates && cliFeedJson) {
const backupVersion: string = runtime === ProjectRuntime.one ? v1ReleaseVersion : betaReleaseVersion;
templates = await templateRetriever.tryGetTemplatesFromCliFeed(this, cliFeedJson, backupVersion, runtime);
this.properties.templateSource = 'backupCliFeed';
}
if (templates) {
// tslint:disable-next-line:strict-boolean-expressions
templatesMap[runtime] = (templatesMap[runtime] || []).concat(templates);
} else {
// Failed to get templates for this runtime
this.properties.templateSource = 'None';
}
});
}
}
return new FunctionTemplates(templatesMap);
}
export function removeLanguageFromId(id: string): string {
return id.split('-')[0];
}
async function tryGetTemplateVersionSetting(context: IActionContext, cliFeedJson: cliFeedJsonResponse | undefined, runtime: ProjectRuntime): Promise<string | undefined> {
const feedRuntime: string = getFeedRuntime(runtime);
const userTemplateVersion: string | undefined = getFuncExtensionSetting(templateVersionSetting);
try {
if (userTemplateVersion) {
context.properties.userTemplateVersion = userTemplateVersion;
}
let templateVersion: string;
if (cliFeedJson) {
templateVersion = userTemplateVersion ? userTemplateVersion : cliFeedJson.tags[feedRuntime].release;
// tslint:disable-next-line:strict-boolean-expressions
if (!cliFeedJson.releases[templateVersion]) {
const invalidVersion: string = localize('invalidTemplateVersion', 'Failed to retrieve Azure Functions templates for version "{0}".', templateVersion);
const selectVersion: vscode.MessageItem = { title: localize('selectVersion', 'Select version') };
const useLatest: vscode.MessageItem = { title: localize('useLatest', 'Use latest') };
const warningInput: vscode.MessageItem = await ext.ui.showWarningMessage(invalidVersion, selectVersion, useLatest);
if (warningInput === selectVersion) {
const releaseQuickPicks: vscode.QuickPickItem[] = [];
for (const rel of Object.keys(cliFeedJson.releases)) {
releaseQuickPicks.push({
label: rel,
description: ''
});
}
const input: vscode.QuickPickItem | undefined = await ext.ui.showQuickPick(releaseQuickPicks, { placeHolder: invalidVersion });
templateVersion = input.label;
await updateGlobalSetting(templateVersionSetting, input.label);
} else {
templateVersion = cliFeedJson.tags[feedRuntime].release;
// reset user setting so that it always gets latest
await updateGlobalSetting(templateVersionSetting, '');
}
}
} else {
return undefined;
}
return templateVersion;
} catch (error) {
// if cliJson does not have the template version being searched for, it will throw an error
context.properties.userTemplateVersion = parseError(error).message;
return undefined;
}
}

Просмотреть файл

@ -0,0 +1,51 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from '../localize';
export enum ValueType {
string = 'string',
boolean = 'boolean',
enum = 'enum',
checkBoxList = 'checkBoxList',
int = 'int'
}
export enum ResourceType {
DocumentDB = 'DocumentDB',
Storage = 'Storage',
EventHub = 'EventHub'
}
export function getResourceTypeLabel(resourceType: ResourceType): string {
switch (resourceType) {
case ResourceType.DocumentDB:
return localize('azFunc.DocumentDB', 'Cosmos DB Account');
case ResourceType.Storage:
return localize('azFunc.Storage', 'Storage Account');
case ResourceType.EventHub:
return localize('azFunc.EventHub', 'Event Hub');
default:
return resourceType;
}
}
export interface IEnumValue {
value: string;
displayName: string;
}
/**
* Describes a setting used when creating a function trigger (i.e. 'AuthorizationLevel' for an HttpTrigger or 'Schedule' for a TimerTrigger)
*/
export interface IFunctionSetting {
resourceType: ResourceType | undefined;
valueType: ValueType | undefined;
defaultValue: string | undefined;
enums: IEnumValue[];
label: string;
name: string;
validateSetting(value: string | undefined): string | undefined;
}

Просмотреть файл

@ -0,0 +1,23 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IFunctionSetting } from './IFunctionSetting';
export enum TemplateCategory {
Core = '$temp_category_core'
}
/**
* Describes a template used for creating a function trigger (i.e. an HttpTrigger or TimerTrigger)
*/
export interface IFunctionTemplate {
id: string;
name: string;
defaultFunctionName: string;
language: string;
isHttpTrigger: boolean;
userPromptedSettings: IFunctionSetting[];
categories: TemplateCategory[];
}

Просмотреть файл

@ -1,9 +1,16 @@
# Azure Function Templates
The code in this folder is used to parse and model the [function templates](https://github.com/Azure/azure-webjobs-sdk-templates) provided by the [Azure Functions portal](https://functions.azure.com/signin). The portal provides template data in three parts: templates.json, bindingconfig.json, and resources.json. See below for an example of the schema for the TimerTrigger template
The code in this folder is used to parse and model the [function templates](https://github.com/Azure/azure-webjobs-sdk-templates) provided by the [Azure Functions CLI Feed](https://aka.ms/V00v5v). The Functions CLI Feed provides a central location to get the latest version of all templates used for functions. Currently, this repo leverages the following templates:
* [Script Templates](#script-templates) (i.e. JavaScript, C#Script, and Python)
* [.NET Templates](#.net-templates) (i.e. C#)
## Script Templates
Script templates are retrieved from the 'templateApiZip' property in the CLI Feed. The zip contains data in three parts: templates.json, bindingconfig.json, and resources.json. See below for an example of the schema for the TimerTrigger template:
### Templates.json
## Templates.json
[https://functions.azure.com/api/templates?runtime=~2](https://functions.azure.com/api/templates?runtime=~2)
```json
[
{
@ -43,8 +50,8 @@ The code in this folder is used to parse and model the [function templates](http
]
```
## BindingConfig.json
[https://functions.azure.com/api/bindingconfig?runtime=~2](https://functions.azure.com/api/bindingconfig?runtime=~2)
### BindingConfig.json
```json
{
"$schema": "<TBD>",
@ -94,8 +101,8 @@ The code in this folder is used to parse and model the [function templates](http
}
```
## Resources.json
[https://functions.azure.com/api/resources?runtime=~2&name=en-us](https://functions.azure.com/api/resources?runtime=~2&name=en-us)
### Resources.json
```json
{
"lang": {},
@ -113,3 +120,47 @@ The code in this folder is used to parse and model the [function templates](http
}
}
```
## .NET Templates
.NET templates are retrieved from the 'itemTemplates' and 'projectTemplates' properties in the CLI Feed. These properties reference two nuget packages. We then leverage the 'Microsoft.TemplateEngine.JsonCli' dll which provides a JSON-based way to interact with .NET templates.
The following is an example command used to list templates:
```
dotnet <path to extension>/resources/dotnetJsonCli/Microsoft.TemplateEngine.JsonCli.dll --require <path to extension>/resources/dotnetTemplates/itemTemplates-~1.nupkg --require <path to extension>/resources/dotnetTemplates/projectTemplates-~1.nupkg --operation list
```
Example format for the Timer Trigger:
```json
{
"Author": "Microsoft",
"Classifications": [
"Azure Function"
],
"DefaultName": "TimerTriggerCSharp",
"Identity": "Azure.Function.CSharp.TimerTrigger.1.x",
"GroupIdentity": "Azure.Function.TimerTrigger",
"Name": "TimerTrigger",
"ShortName": "Timer",
"Parameters": [
{
"Documentation": "Enter a cron expression of the format '{second} {minute} {hour} {day} {month} {day of week}' to specify the schedule.",
"Name": "Schedule",
"Priority": 0,
"Type": null,
"IsName": false,
"DefaultValue": "0 */5 * * * *",
"DataType": null,
"Choices": null
}
]
}
```
And the following is an example command for creating a template:
```
dotnet <path to extension>/resources/dotnetJsonCli/Microsoft.TemplateEngine.JsonCli.dll --require <path to extension>/resources/dotnetTemplates/itemTemplates-beta.nupkg --require <path to extension>/resources/dotnetTemplates/projectTemplates-beta.nupkg --operation create --identity Azure.Function.CSharp.TimerTrigger.2.x --arg:Schedule 0 */5 * * * * --arg:name TimerTriggerCSharp --arg:namespace Company.Function
```

Просмотреть файл

@ -1,21 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
interface IResources {
en: { [key: string]: string };
}
export class Resources {
private _resources: IResources;
constructor(data: object) {
this._resources = <IResources>data;
}
public getValue(data: string): string {
const matches: RegExpMatchArray | null = data.match(/\$(.*)/);
return matches !== null ? this._resources.en[matches[1]] : data;
}
}

Просмотреть файл

@ -0,0 +1,97 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as extract from 'extract-zip';
import * as fse from 'fs-extra';
import * as os from 'os';
import * as path from 'path';
import { ProjectRuntime } from '../constants';
import { ext } from '../extensionVariables';
import { downloadFile } from '../utils/fs';
import { cliFeedJsonResponse } from '../utils/getCliFeedJson';
import { IFunctionTemplate } from './IFunctionTemplate';
import { parseScriptTemplates } from './parseScriptTemplates';
import { TemplateRetriever, TemplateType } from './TemplateRetriever';
export class ScriptTemplateRetriever extends TemplateRetriever {
public templateType: TemplateType = TemplateType.Script;
private _templatesKey: string = 'FunctionTemplates';
private _configKey: string = 'FunctionTemplateConfig';
private _resourcesKey: string = 'FunctionTemplateResources';
private _tempPath: string = path.join(os.tmpdir(), 'vscode-azurefunctions-templates');
private _rawResources: object;
private _rawTemplates: object[];
private _rawConfig: object;
public getVerifiedTemplateIds(runtime: ProjectRuntime): string[] {
return getScriptVerifiedTemplateIds(runtime);
}
protected async getTemplatesFromCache(runtime: ProjectRuntime): Promise<IFunctionTemplate[] | undefined> {
const cachedResources: object | undefined = ext.context.globalState.get<object>(this.getCacheKey(this._resourcesKey, runtime));
const cachedTemplates: object[] | undefined = ext.context.globalState.get<object[]>(this.getCacheKey(this._templatesKey, runtime));
const cachedConfig: object | undefined = ext.context.globalState.get<object>(this.getCacheKey(this._configKey, runtime));
if (cachedResources && cachedTemplates && cachedConfig) {
return parseScriptTemplates(cachedResources, cachedTemplates, cachedConfig);
} else {
return undefined;
}
}
protected async getTemplatesFromCliFeed(cliFeedJson: cliFeedJsonResponse, templateVersion: string, _runtime: ProjectRuntime): Promise<IFunctionTemplate[]> {
try {
const filePath: string = path.join(this._tempPath, `templates-${templateVersion}.zip`);
await downloadFile(cliFeedJson.releases[templateVersion].templateApiZip, filePath);
await new Promise(async (resolve: () => void, reject: (e: Error) => void): Promise<void> => {
// tslint:disable-next-line:no-unsafe-any
extract(filePath, { dir: this._tempPath }, (err: Error) => {
// tslint:disable-next-line:strict-boolean-expressions
if (err) {
reject(err);
}
resolve();
});
});
// only Resources.json has a capital letter
this._rawResources = <object>await fse.readJSON(path.join(this._tempPath, 'resources', 'Resources.json'));
this._rawTemplates = <object[]>await fse.readJSON(path.join(this._tempPath, 'templates', 'templates.json'));
this._rawConfig = <object>await fse.readJSON(path.join(this._tempPath, 'bindings', 'bindings.json'));
return parseScriptTemplates(this._rawResources, this._rawTemplates, this._rawConfig);
} finally {
if (await fse.pathExists(this._tempPath)) {
await fse.remove(this._tempPath);
}
}
}
protected async cacheTemplatesFromCliFeed(runtime: ProjectRuntime): Promise<void> {
ext.context.globalState.update(this.getCacheKey(this._templatesKey, runtime), this._rawTemplates);
ext.context.globalState.update(this.getCacheKey(this._configKey, runtime), this._rawConfig);
ext.context.globalState.update(this.getCacheKey(this._resourcesKey, runtime), this._rawResources);
}
}
export function getScriptVerifiedTemplateIds(runtime: string): string[] {
let verifiedTemplateIds: string[] = [
'BlobTrigger-JavaScript',
'HttpTrigger-JavaScript',
'QueueTrigger-JavaScript',
'TimerTrigger-JavaScript'
];
if (runtime === ProjectRuntime.one) {
verifiedTemplateIds = verifiedTemplateIds.concat([
'GenericWebHook-JavaScript',
'GitHubWebHook-JavaScript',
'HttpTriggerWithParameters-JavaScript',
'ManualTrigger-JavaScript'
]);
}
return verifiedTemplateIds;
}

Просмотреть файл

@ -1,68 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ProjectLanguage } from '../constants';
import { FunctionConfig } from '../FunctionConfig';
import { Resources } from './Resources';
interface ITemplate {
id: string;
// tslint:disable-next-line:no-reserved-keywords
function: {};
metadata: ITemplateMetadata;
files: { [filename: string]: string };
}
interface ITemplateMetadata {
defaultFunctionName: string;
name: string;
language: ProjectLanguage;
userPrompt?: string[];
category: TemplateCategory[];
}
export enum TemplateCategory {
Core = '$temp_category_core'
}
export class Template {
public readonly functionConfig: FunctionConfig;
private _template: ITemplate;
private _resources: Resources;
constructor(template: object, resources: Resources) {
this._template = <ITemplate>template;
this._resources = resources;
this.functionConfig = new FunctionConfig(this._template.function);
}
public get id(): string {
return this._template.id;
}
public get name(): string {
return this._resources.getValue(this._template.metadata.name);
}
public get defaultFunctionName(): string {
return this._template.metadata.defaultFunctionName;
}
public get language(): ProjectLanguage {
return this._template.metadata.language;
}
public isCategory(category: TemplateCategory): boolean {
return this._template.metadata.category.find((c: TemplateCategory) => c === category) !== undefined;
}
public get userPromptedSettings(): string[] {
return this._template.metadata.userPrompt ? this._template.metadata.userPrompt : [];
}
public get templateFiles(): { [filename: string]: string } {
return this._template.files;
}
}

Просмотреть файл

@ -1,323 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as extract from 'extract-zip';
import * as fse from 'fs-extra';
import * as os from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import { callWithTelemetryAndErrorHandling, IActionContext, parseError } from 'vscode-azureextensionui';
import { betaReleaseVersion, ProjectLanguage, ProjectRuntime, TemplateFilter, templateVersionSetting, v1ReleaseVersion } from '../constants';
import { ext } from '../extensionVariables';
import { localize } from '../localize';
import { getFuncExtensionSetting, updateGlobalSetting } from '../ProjectSettings';
import { downloadFile } from '../utils/fs';
import { cliFeedJsonResponse, getFeedRuntime, tryGetCliFeedJson } from '../utils/getCliFeedJson';
import { Config } from './Config';
import { ConfigBinding } from './ConfigBinding';
import { ConfigSetting } from './ConfigSetting';
import { Resources } from './Resources';
import { Template, TemplateCategory } from './Template';
export type parsedTemplates = [Template[], Config];
const templatesKey: string = 'FunctionTemplates';
const configKey: string = 'FunctionTemplateConfig';
const resourcesKey: string = 'FunctionTemplateResources';
const templateVersionKey: string = 'templateVersion';
const tempPath: string = path.join(os.tmpdir(), 'vscode-azurefunctions-templates');
const verifiedTemplates: string[] = [
'BlobTrigger-JavaScript',
'GenericWebHook-JavaScript',
'GitHubWebHook-JavaScript',
'HttpTrigger-JavaScript',
'HttpTriggerWithParameters-JavaScript',
'ManualTrigger-JavaScript',
'QueueTrigger-JavaScript',
'TimerTrigger-JavaScript'
];
const verifiedCSharpTemplates: string[] = [
'HttpTrigger-CSharp',
'BlobTrigger-CSharp',
'QueueTrigger-CSharp',
'TimerTrigger-CSharp'
];
const verifiedJavaTemplates: string[] = [
'HttpTrigger',
'BlobTrigger',
'QueueTrigger',
'TimerTrigger'
];
/**
* Main container for all template data retrieved from the Azure Functions Portal. See README.md for more info and example of the schema.
* We cache the template data retrieved from the portal so that the user can create functions offline.
*/
export class TemplateData {
private readonly _templatesMap: { [runtime: string]: Template[] | undefined } = {};
private readonly _configMap: { [runtime: string]: Config | undefined } = {};
// if there are no templates, then there is likely no internet or a problem with the clifeed url
private readonly _noInternetErrMsg: string = localize('retryInternet', 'There was an error in retrieving the templates. Recheck your internet connection and try again.');
constructor(templatesMap: { [runtime: string]: Template[] | undefined }, configMap: { [runtime: string]: Config | undefined }) {
this._templatesMap = templatesMap;
this._configMap = configMap;
}
public async getTemplates(language: string, runtime: string = ProjectRuntime.one, templateFilter?: string): Promise<Template[]> {
const templates: Template[] | undefined = this._templatesMap[runtime];
if (!templates) {
throw new Error(this._noInternetErrMsg);
}
if (language === ProjectLanguage.Java) {
// Currently we leverage JS templates to get the function metadata of Java Functions.
// Will refactor the code here when templates HTTP API is ready.
// See issue here: https://github.com/Microsoft/vscode-azurefunctions/issues/84
const javaTemplates: Template[] = templates.filter((t: Template) => t.language === ProjectLanguage.JavaScript);
return javaTemplates.filter((t: Template) => verifiedJavaTemplates.find((vt: string) => vt === removeLanguageFromId(t.id)));
} else if (language === ProjectLanguage.CSharp) {
// https://github.com/Microsoft/vscode-azurefunctions/issues/179
return templates.filter((t: Template) => verifiedCSharpTemplates.some((id: string) => id === t.id));
} else {
switch (language) {
case ProjectLanguage.CSharpScript:
case ProjectLanguage.FSharpScript:
// The functions portal only supports script languages, so it doesn't have the notion of 'C#' vs 'C#Script'
language = language.replace('Script', '');
break;
default:
}
let filterTemplates: Template[] = templates.filter((t: Template) => t.language.toLowerCase() === language.toLowerCase());
switch (templateFilter) {
case TemplateFilter.All:
break;
case TemplateFilter.Core:
filterTemplates = filterTemplates.filter((t: Template) => t.isCategory(TemplateCategory.Core));
break;
case TemplateFilter.Verified:
default:
filterTemplates = filterTemplates.filter((t: Template) => verifiedTemplates.find((vt: string) => vt === t.id));
}
return filterTemplates;
}
}
public async getSetting(runtime: ProjectRuntime, bindingType: string, settingName: string): Promise<ConfigSetting | undefined> {
const config: Config | undefined = this._configMap[runtime];
if (!config) {
throw new Error(this._noInternetErrMsg);
}
const binding: ConfigBinding | undefined = config.bindings.find((b: ConfigBinding) => b.bindingType === bindingType);
if (binding) {
return binding.settings.find((bs: ConfigSetting) => bs.name === settingName);
} else {
return undefined;
}
}
}
function verifyTemplatesByRuntime(templates: Template[], runtime: ProjectRuntime): void {
if (runtime === ProjectRuntime.one) {
for (const verifiedTemplateId of verifiedTemplates) {
if (!templates.some((t: Template) => t.id === verifiedTemplateId)) {
throw new Error(localize('failedToFindJavaScriptTemplate', 'Failed to find verified template with id "{0}".', verifiedTemplateId));
}
}
for (const verifiedTemplateId of verifiedCSharpTemplates) {
if (!templates.some((t: Template) => t.id === verifiedTemplateId)) {
throw new Error(localize('failedToFindCSharpTemplate', 'Failed to find verified template with id "{0}".', verifiedTemplateId));
}
}
} else if (runtime === ProjectRuntime.beta) {
for (const verifiedTemplateId of verifiedCSharpTemplates) {
if (!templates.some((t: Template) => t.id === verifiedTemplateId)) {
throw new Error(localize('failedToFindCSharpTemplate', 'Failed to find verified template with id "{0}".', verifiedTemplateId));
}
}
}
}
export async function getTemplateData(globalState?: vscode.Memento): Promise<TemplateData> {
const templatesMap: { [runtime: string]: Template[] | undefined } = {};
const configMap: { [runtime: string]: Config | undefined } = {};
const cliFeedJson: cliFeedJsonResponse | undefined = await tryGetCliFeedJson();
for (const key of Object.keys(ProjectRuntime)) {
await callWithTelemetryAndErrorHandling('azureFunctions.getTemplateData', async function (this: IActionContext): Promise<void> {
this.suppressErrorDisplay = true;
this.properties.isActivationEvent = 'true';
const runtime: ProjectRuntime = <ProjectRuntime>ProjectRuntime[key];
this.properties.runtime = runtime;
const templateVersion: string | undefined = await tryGetTemplateVersionSetting(this, cliFeedJson, runtime);
let parsedTemplatesByRuntime: parsedTemplates | undefined;
// 1. Use the cached templates if they match templateVersion
if (globalState && globalState.get(`${templateVersionKey}-${runtime}`) === templateVersion) {
parsedTemplatesByRuntime = await tryGetParsedTemplateDataFromCache(this, runtime, globalState);
this.properties.templateSource = 'matchingCache';
}
// 2. Download templates from the cli-feed if the cache doesn't match templateVersion
if (!parsedTemplatesByRuntime && cliFeedJson && templateVersion) {
parsedTemplatesByRuntime = await tryGetParsedTemplateDataFromCliFeed(this, cliFeedJson, templateVersion, runtime, globalState);
this.properties.templateSource = 'cliFeed';
}
// 3. Use the cached templates, even if they don't match templateVersion
if (!parsedTemplatesByRuntime && globalState) {
parsedTemplatesByRuntime = await tryGetParsedTemplateDataFromCache(this, runtime, globalState);
this.properties.templateSource = 'mismatchCache';
}
// 4. Download templates from the cli-feed using the backupVersion
if (!parsedTemplatesByRuntime && cliFeedJson) {
const backupVersion: string = runtime === ProjectRuntime.one ? v1ReleaseVersion : betaReleaseVersion;
parsedTemplatesByRuntime = await tryGetParsedTemplateDataFromCliFeed(this, cliFeedJson, backupVersion, runtime, globalState);
this.properties.templateSource = 'backupCliFeed';
}
if (parsedTemplatesByRuntime) {
[templatesMap[runtime], configMap[runtime]] = parsedTemplatesByRuntime;
} else {
// Failed to get templates for this runtime
this.properties.templateSource = 'None';
}
});
}
return new TemplateData(templatesMap, configMap);
}
async function tryGetParsedTemplateDataFromCache(context: IActionContext, runtime: ProjectRuntime, globalState: vscode.Memento): Promise<parsedTemplates | undefined> {
try {
const cachedResources: object | undefined = globalState.get<object>(getRuntimeKey(resourcesKey, runtime));
const cachedTemplates: object[] | undefined = globalState.get<object[]>(getRuntimeKey(templatesKey, runtime));
const cachedConfig: object | undefined = globalState.get<object>(getRuntimeKey(configKey, runtime));
if (cachedResources && cachedTemplates && cachedConfig) {
return parseTemplates(cachedResources, cachedTemplates, cachedConfig);
}
} catch (error) {
context.properties.cacheError = parseError(error).message;
}
return undefined;
}
async function tryGetParsedTemplateDataFromCliFeed(context: IActionContext, cliFeedJson: cliFeedJsonResponse, templateVersion: string, runtime: ProjectRuntime, globalState?: vscode.Memento): Promise<parsedTemplates | undefined> {
try {
context.properties.templateVersion = templateVersion;
await downloadAndExtractTemplates(cliFeedJson.releases[templateVersion].templateApiZip, templateVersion);
// only Resources.json has a capital letter
const rawResources: object = <object>await fse.readJSON(path.join(tempPath, 'resources', 'Resources.json'));
const rawTemplates: object[] = <object[]>await fse.readJSON(path.join(tempPath, 'templates', 'templates.json'));
const rawConfig: object = <object>await fse.readJSON(path.join(tempPath, 'bindings', 'bindings.json'));
const parsedTemplatesByRuntime: parsedTemplates = parseTemplates(rawResources, rawTemplates, rawConfig);
verifyTemplatesByRuntime(parsedTemplatesByRuntime[0], runtime);
if (globalState) {
globalState.update(`${templateVersionKey}-${runtime}`, templateVersion);
globalState.update(getRuntimeKey(templatesKey, runtime), rawTemplates);
globalState.update(getRuntimeKey(configKey, runtime), rawConfig);
globalState.update(getRuntimeKey(resourcesKey, runtime), rawResources);
}
return parsedTemplatesByRuntime;
} catch (error) {
context.properties.cliFeedError = parseError(error).message;
return undefined;
} finally {
if (await fse.pathExists(tempPath)) {
await fse.remove(tempPath);
}
}
}
function getRuntimeKey(baseKey: string, runtime: ProjectRuntime): string {
return runtime === ProjectRuntime.one ? baseKey : `${baseKey}.${runtime}`;
}
function parseTemplates(rawResources: object, rawTemplates: object[], rawConfig: object): parsedTemplates {
const resources: Resources = new Resources(rawResources);
const templates: Template[] = [];
for (const rawTemplate of rawTemplates) {
try {
templates.push(new Template(rawTemplate, resources));
} catch (error) {
// Ignore errors so that a single poorly formed template does not affect other templates
}
}
return [templates, new Config(rawConfig, resources)];
}
export function removeLanguageFromId(id: string): string {
return id.split('-')[0];
}
async function downloadAndExtractTemplates(templateUrl: string, release: string): Promise<{}> {
const filePath: string = path.join(tempPath, `templates-${release}.zip`);
ext.outputChannel.appendLine(localize('downloadTemplates', 'Downloading "v{0}" templates zip file. . .', release));
await fse.ensureDir(tempPath);
await downloadFile(templateUrl, filePath);
return new Promise(async (resolve: () => void, reject: (e: Error) => void): Promise<void> => {
// tslint:disable-next-line:no-unsafe-any
extract(filePath, { dir: tempPath }, (err: Error) => {
// tslint:disable-next-line:strict-boolean-expressions
if (err) {
reject(err);
}
ext.outputChannel.appendLine(localize('templatesExtracted', 'Template files extracted.'));
resolve();
});
});
}
export async function tryGetTemplateVersionSetting(context: IActionContext, cliFeedJson: cliFeedJsonResponse | undefined, runtime: ProjectRuntime): Promise<string | undefined> {
const feedRuntime: string = getFeedRuntime(runtime);
const userTemplateVersion: string | undefined = getFuncExtensionSetting(templateVersionSetting);
try {
if (userTemplateVersion) {
context.properties.userTemplateVersion = userTemplateVersion;
}
let templateVersion: string;
if (cliFeedJson) {
templateVersion = userTemplateVersion ? userTemplateVersion : cliFeedJson.tags[feedRuntime].release;
// tslint:disable-next-line:strict-boolean-expressions
if (!cliFeedJson.releases[templateVersion]) {
const invalidVersion: string = localize('invalidTemplateVersion', 'Failed to retrieve Azure Functions templates for version "{0}".', templateVersion);
const selectVersion: vscode.MessageItem = { title: localize('selectVersion', 'Select version') };
const useLatest: vscode.MessageItem = { title: localize('useLatest', 'Use latest') };
const warningInput: vscode.MessageItem = await ext.ui.showWarningMessage(invalidVersion, selectVersion, useLatest);
if (warningInput === selectVersion) {
const releaseQuickPicks: vscode.QuickPickItem[] = [];
for (const rel of Object.keys(cliFeedJson.releases)) {
releaseQuickPicks.push({
label: rel,
description: ''
});
}
const input: vscode.QuickPickItem | undefined = await ext.ui.showQuickPick(releaseQuickPicks, { placeHolder: invalidVersion });
templateVersion = input.label;
await updateGlobalSetting(templateVersionSetting, input.label);
} else {
templateVersion = cliFeedJson.tags[feedRuntime].release;
// reset user setting so that it always gets latest
await updateGlobalSetting(templateVersionSetting, '');
}
}
} else {
return undefined;
}
return templateVersion;
} catch (error) {
// if cliJson does not have the template version being searched for, it will throw an error
context.properties.userTemplateVersion = parseError(error).message;
return undefined;
}
}

Просмотреть файл

@ -0,0 +1,81 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IActionContext, parseError } from 'vscode-azureextensionui';
import { ProjectRuntime } from '../constants';
import { ext } from '../extensionVariables';
import { localize } from '../localize';
import { cliFeedJsonResponse } from '../utils/getCliFeedJson';
import { IFunctionTemplate } from './IFunctionTemplate';
export enum TemplateType {
Script = 'Script',
Dotnet = '.NET'
}
export abstract class TemplateRetriever {
public static templateVersionKey: string = 'templateVersion';
public abstract templateType: TemplateType;
public async tryGetTemplatesFromCache(context: IActionContext, runtime: ProjectRuntime): Promise<IFunctionTemplate[] | undefined> {
try {
return await this.getTemplatesFromCache(runtime);
} catch (error) {
const errorMessage: string = parseError(error).message;
ext.outputChannel.appendLine(errorMessage);
context.properties.cacheError = errorMessage;
return undefined;
}
}
public async tryGetTemplatesFromCliFeed(context: IActionContext, cliFeedJson: cliFeedJsonResponse, templateVersion: string, runtime: ProjectRuntime): Promise<IFunctionTemplate[] | undefined> {
try {
context.properties.templateVersion = templateVersion;
ext.outputChannel.appendLine(localize('updatingTemplates', 'Updating {0} templates for runtime "{1}" to version "{2}"...', this.templateType, runtime, templateVersion));
const templates: IFunctionTemplate[] = await this.getTemplatesFromCliFeed(cliFeedJson, templateVersion, runtime);
await this.verifyTemplates(templates, runtime);
ext.context.globalState.update(this.getCacheKey(TemplateRetriever.templateVersionKey, runtime), templateVersion);
await this.cacheTemplatesFromCliFeed(runtime);
ext.outputChannel.appendLine(localize('updatedTemplates', 'Successfully updated templates.'));
return templates;
} catch (error) {
const errorMessage: string = parseError(error).message;
ext.outputChannel.appendLine(errorMessage);
context.properties.cliFeedError = errorMessage;
return undefined;
}
}
/**
* Adds runtime and templateType information to a key to ensure there are no collisions in the cache
* For backwards compatability, the original runtime and templateType will not have this information
*/
public getCacheKey(key: string, runtime: ProjectRuntime): string {
if (runtime !== ProjectRuntime.one) {
key = `${key}.${runtime}`;
}
if (this.templateType !== TemplateType.Script) {
key = `${key}.${this.templateType}`;
}
return key;
}
protected abstract getTemplatesFromCache(runtime: ProjectRuntime): Promise<IFunctionTemplate[] | undefined>;
protected abstract getTemplatesFromCliFeed(cliFeedJson: cliFeedJsonResponse, templateVersion: string, runtime: ProjectRuntime): Promise<IFunctionTemplate[]>;
protected abstract cacheTemplatesFromCliFeed(runtime: ProjectRuntime): Promise<void>;
protected abstract getVerifiedTemplateIds(runtime: ProjectRuntime): string[];
private async verifyTemplates(templates: IFunctionTemplate[], runtime: ProjectRuntime): Promise<void> {
const verifiedTemplateIds: string[] = this.getVerifiedTemplateIds(runtime);
for (const verifiedTemplateId of verifiedTemplateIds) {
if (!templates.some((t: IFunctionTemplate) => t.id === verifiedTemplateId)) {
throw new Error(localize('failedToVerifiedTemplate', 'Failed to find verified template with id "{0}".', verifiedTemplateId));
}
}
}
}

Просмотреть файл

@ -0,0 +1,26 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as path from 'path';
import { ProjectRuntime } from '../constants';
import { ext } from "../extensionVariables";
import { cpUtils } from "../utils/cpUtils";
export async function executeDotnetTemplateCommand(runtime: ProjectRuntime, workingDirectory: string | undefined, operation: 'list' | 'create', ...args: string[]): Promise<string> {
const jsonDllPath: string = ext.context.asAbsolutePath(path.join('resources', 'dotnetJsonCli', 'Microsoft.TemplateEngine.JsonCli.dll'));
return await cpUtils.executeCommand(undefined, workingDirectory, 'dotnet', jsonDllPath, '--require', getDotnetItemTemplatePath(runtime), '--require', getDotnetProjectTemplatePath(runtime), '--operation', operation, ...args);
}
export function getDotnetTemplatesPath(): string {
return ext.context.asAbsolutePath(path.join('resources', 'dotnetTemplates'));
}
export function getDotnetItemTemplatePath(runtime: ProjectRuntime): string {
return path.join(getDotnetTemplatesPath(), `itemTemplates-${runtime}.nupkg`);
}
export function getDotnetProjectTemplatePath(runtime: ProjectRuntime): string {
return path.join(getDotnetTemplatesPath(), `projectTemplates-${runtime}.nupkg`);
}

Просмотреть файл

@ -0,0 +1,84 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ProjectLanguage, ProjectRuntime } from '../constants';
import { IFunctionSetting, ValueType } from './IFunctionSetting';
import { IFunctionTemplate, TemplateCategory } from './IFunctionTemplate';
/**
* Describes a dotnet template before it has been parsed
*/
interface IRawTemplate {
DefaultName: string;
Name: string;
Identity: string;
Parameters: {}[];
}
/**
* Describes a dotnet template setting before it has been parsed
*/
interface IRawSetting {
Documentation: string | undefined;
Name: string;
DefaultValue: string | undefined;
DataType: string | undefined;
Choices: {
[key: string]: string;
} | undefined;
}
function parseDotnetSetting(rawSetting: IRawSetting): IFunctionSetting {
return {
name: rawSetting.Name,
resourceType: undefined, // Dotnet templates do not give us resourceType information
valueType: rawSetting.DataType === 'choice' ? ValueType.enum : ValueType.string,
defaultValue: rawSetting.DefaultValue,
label: rawSetting.Name,
enums: rawSetting.Choices ? Object.keys(rawSetting.Choices).map((key: string) => { return { value: key, displayName: key }; }) : [],
validateSetting: (): undefined => { return undefined; } // Dotnet templates do not give us validation information
};
}
function parseDotnetTemplate(rawTemplate: IRawTemplate): IFunctionTemplate {
const userPromptedSettings: IFunctionSetting[] = [];
for (const rawSetting of rawTemplate.Parameters) {
const setting: IFunctionSetting = parseDotnetSetting(<IRawSetting>rawSetting);
// Exclude some of the default parameters like 'name' and 'namespace' that apply for every function and are handled separately
if (!/^(name|namespace|type|language)$/i.test(setting.name)) {
userPromptedSettings.push(setting);
}
}
return {
isHttpTrigger: rawTemplate.Name.toLowerCase().startsWith('http') || rawTemplate.Name.toLowerCase().endsWith('webhook'),
id: rawTemplate.Identity,
name: rawTemplate.Name,
defaultFunctionName: rawTemplate.DefaultName,
language: ProjectLanguage.CSharp,
userPromptedSettings: userPromptedSettings,
categories: [TemplateCategory.Core] // Dotnet templates do not have category information, so display all templates as if they are in the 'core' category
};
}
/**
* Parses templates used by the .NET CLI
* This basically converts the 'raw' templates in the externally defined JSON format to a common and understood format (IFunctionTemplate) used by this extension
*/
export function parseDotnetTemplates(rawTemplates: object[], runtime: ProjectRuntime): IFunctionTemplate[] {
const templates: IFunctionTemplate[] = [];
for (const rawTemplate of rawTemplates) {
try {
const template: IFunctionTemplate = parseDotnetTemplate(<IRawTemplate>rawTemplate);
if (template.id.startsWith('Azure.Function.CSharp.') &&
((runtime === ProjectRuntime.one && template.id.includes('1')) || (runtime === ProjectRuntime.beta && template.id.includes('2')))) {
templates.push(template);
}
} catch (error) {
// Ignore errors so that a single poorly formed template does not affect other templates
}
}
return templates;
}

Просмотреть файл

@ -0,0 +1,195 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { isString } from 'util';
import { ProjectLanguage } from '../constants';
import { FunctionConfig } from '../FunctionConfig';
import { IEnumValue, IFunctionSetting, ResourceType, ValueType } from './IFunctionSetting';
import { IFunctionTemplate, TemplateCategory } from './IFunctionTemplate';
/**
* Describes a script template before it has been parsed
*/
interface IRawTemplate {
id: string;
// tslint:disable-next-line:no-reserved-keywords
function: {};
metadata: {
defaultFunctionName: string;
name: string;
language: ProjectLanguage;
userPrompt?: string[];
category: TemplateCategory[];
};
files: { [filename: string]: string };
}
/**
* Describes a script template setting before it has been parsed
*/
interface IRawSetting {
name: string;
value: ValueType;
label: string;
defaultValue?: string;
required: boolean;
resource?: ResourceType;
validators?: {
expression: string;
errorText: string;
}[];
// tslint:disable-next-line:no-reserved-keywords
enum?: {
value: string;
display: string;
}[];
}
/**
* Describes script template config to be used for parsing
*/
interface IConfig {
variables: IVariables;
bindings: {
// tslint:disable-next-line:no-reserved-keywords
type: string;
settings: object[];
}[];
}
/**
* Describes script template variables to be used for parsing
*/
interface IVariables { [name: string]: string; }
/**
* Describes script template resources to be used for parsing
*/
interface IResources { en: { [key: string]: string }; }
// tslint:disable-next-line:no-any
function getVariableValue(resources: IResources, variables: IVariables, data: string): string {
if (!isString(data)) {
// This evaluates to a non-string value in rare cases, in which case we just return the value as-is
return data;
}
const matches: RegExpMatchArray | null = data.match(/\[variables\(\'(.*)\'\)\]/);
data = matches !== null ? variables[matches[1]] : data;
return getResourceValue(resources, <string>data);
}
function getResourceValue(resources: IResources, data: string): string {
const matches: RegExpMatchArray | null = data.match(/\$(.*)/);
return matches !== null ? resources.en[matches[1]] : data;
}
function parseScriptSetting(data: object, resources: IResources, variables: IVariables): IFunctionSetting {
const rawSetting: IRawSetting = <IRawSetting>data;
const enums: IEnumValue[] = [];
if (rawSetting.enum) {
for (const ev of rawSetting.enum) {
enums.push({
value: getVariableValue(resources, variables, ev.value),
displayName: getVariableValue(resources, variables, ev.display)
});
}
}
return {
name: getVariableValue(resources, variables, rawSetting.name),
resourceType: rawSetting.resource,
valueType: rawSetting.value,
defaultValue: rawSetting.defaultValue ? getVariableValue(resources, variables, rawSetting.defaultValue) : undefined,
label: getVariableValue(resources, variables, rawSetting.label),
enums: enums,
validateSetting: (value: string | undefined): string | undefined => {
if (rawSetting.validators) {
for (const validator of rawSetting.validators) {
if (!value || value.match(validator.expression) === null) {
return getVariableValue(resources, variables, validator.errorText);
}
}
}
return undefined;
}
};
}
function parseScriptTemplate(rawTemplate: IRawTemplate, resources: IResources, commonSettings: IConfig): IScriptFunctionTemplate {
const commonSettingsMap: { [inBindingType: string]: IFunctionSetting[] | undefined } = {};
for (const binding of commonSettings.bindings) {
commonSettingsMap[binding.type] = binding.settings.map((setting: object) => parseScriptSetting(setting, resources, commonSettings.variables));
}
const functionConfig: FunctionConfig = new FunctionConfig(rawTemplate.function);
let language: ProjectLanguage = rawTemplate.metadata.language;
// The templateApiZip only supports script languages, and thus incorrectly defines 'C#Script' as 'C#', etc.
switch (language) {
case ProjectLanguage.CSharp:
language = ProjectLanguage.CSharpScript;
break;
case ProjectLanguage.FSharp:
language = ProjectLanguage.FSharpScript;
break;
default:
}
const userPromptedSettings: IFunctionSetting[] = [];
if (rawTemplate.metadata.userPrompt) {
for (const settingName of rawTemplate.metadata.userPrompt) {
const settings: IFunctionSetting[] | undefined = commonSettingsMap[functionConfig.inBindingType];
if (settings) {
const setting: IFunctionSetting | undefined = settings.find((bs: IFunctionSetting) => bs.name === settingName);
if (setting) {
const functionSpecificDefaultValue: string | undefined = functionConfig.inBinding[setting.name];
if (functionSpecificDefaultValue) {
// overwrite common default value with the function-specific default value
setting.defaultValue = functionSpecificDefaultValue;
}
userPromptedSettings.push(setting);
}
}
}
}
return {
functionConfig: functionConfig,
isHttpTrigger: functionConfig.isHttpTrigger,
id: rawTemplate.id,
functionType: functionConfig.inBindingType,
name: getResourceValue(resources, rawTemplate.metadata.name),
defaultFunctionName: rawTemplate.metadata.defaultFunctionName,
language: language,
userPromptedSettings: userPromptedSettings,
templateFiles: rawTemplate.files,
categories: rawTemplate.metadata.category
};
}
export interface IScriptFunctionTemplate extends IFunctionTemplate {
templateFiles: { [filename: string]: string };
functionType: string;
functionConfig: FunctionConfig;
}
/**
* Parses templates contained in the templateApiZip of the functions cli feed. This contains all 'script' templates, including JavaScript, C#Script, Python, etc.
* This basically converts the 'raw' templates in the externally defined JSON format to a common and understood format (IFunctionTemplate) used by this extension
*/
export function parseScriptTemplates(rawResources: object, rawTemplates: object[], rawConfig: object): IFunctionTemplate[] {
const templates: IFunctionTemplate[] = [];
for (const rawTemplate of rawTemplates) {
try {
templates.push(parseScriptTemplate(<IRawTemplate>rawTemplate, <IResources>rawResources, <IConfig>rawConfig));
} catch (error) {
// Ignore errors so that a single poorly formed template does not affect other templates
}
}
return templates;
}

Просмотреть файл

@ -14,7 +14,7 @@ import { addExtensionUserAgent, AzureTreeDataProvider, AzureWizard, IActionConte
import { ArgumentError } from '../errors';
import { ext } from '../extensionVariables';
import { localize } from '../localize';
import { getResourceTypeLabel, ResourceType } from '../templates/ConfigSetting';
import { getResourceTypeLabel, ResourceType } from '../templates/IFunctionSetting';
function parseResourceId(id: string): RegExpMatchArray {
const matches: RegExpMatchArray | null = id.match(/\/subscriptions\/(.*)\/resourceGroups\/(.*)\/providers\/(.*)\/(.*)/);

Просмотреть файл

@ -3,115 +3,15 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as fse from 'fs-extra';
import * as os from 'os';
import * as path from 'path';
import { QuickPickOptions } from "vscode";
import { callWithTelemetryAndErrorHandling, IActionContext, IAzureQuickPickItem } from 'vscode-azureextensionui';
import { ProjectRuntime } from '../constants';
import { ext } from '../extensionVariables';
import { tryGetLocalRuntimeVersion } from '../funcCoreTools/tryGetLocalRuntimeVersion';
import { localize } from "../localize";
import { tryGetTemplateVersionSetting } from '../templates/TemplateData';
import { cpUtils } from "./cpUtils";
import * as fsUtil from './fs';
import { cliFeedJsonResponse, getFeedRuntime, tryGetCliFeedJson } from './getCliFeedJson';
const projectPackageId: string = 'microsoft.azurefunctions.projecttemplates';
const functionsPackageId: string = 'azure.functions.templates';
const templatesKey: string = 'cSharpFunctionsTemplates';
async function validateDotnetInstalled(): Promise<void> {
try {
await cpUtils.executeCommand(undefined, undefined, 'dotnet', '--version');
} catch (error) {
throw new Error(localize('dotnetNotInstalled', 'You must have the .NET CLI installed to perform this operation.'));
}
}
export namespace dotnetUtils {
export const funcProjectId: string = 'azureFunctionsProjectTemplates';
export async function validateTemplatesInstalled(): Promise<void> {
await validateDotnetInstalled();
const listOutput: string = await cpUtils.executeCommand(undefined, undefined, 'dotnet', 'new', '--list');
const templatesInstalled: boolean = listOutput.includes(funcProjectId) && listOutput.includes('HttpTrigger');
export async function validateDotnetInstalled(): Promise<void> {
try {
await callWithTelemetryAndErrorHandling('azureFunctions.validateDotnetTemplatesInstalled', async function (this: IActionContext): Promise<void> {
this.rethrowError = true;
this.suppressErrorDisplay = true;
this.properties.templatesInstalled = String(templatesInstalled);
const templatesVersion: string | undefined = templatesInstalled ? ext.context.globalState.get(templatesKey) : undefined;
this.properties.installedVersion = <string>templatesVersion;
const cliFeedJson: cliFeedJsonResponse | undefined = await tryGetCliFeedJson();
if (!cliFeedJson) {
throw new Error(localize('retryInternet', 'There was an error in retrieving the templates. Recheck your internet connection and try again.'));
}
let runtime: ProjectRuntime | undefined = await tryGetLocalRuntimeVersion();
if (runtime === undefined) {
const picks: IAzureQuickPickItem<ProjectRuntime>[] = Object.keys(ProjectRuntime).map((key: string) => {
const val: ProjectRuntime = <ProjectRuntime>ProjectRuntime[key];
return {
label: cliFeedJson.tags[getFeedRuntime(val)].displayName,
description: '',
data: val
};
});
const options: QuickPickOptions = { placeHolder: localize('pickTemplateVersion', 'Select the template version to install') };
runtime = (await ext.ui.showQuickPick(picks, options)).data;
}
const latestRelease: string = await tryGetTemplateVersionSetting(this, cliFeedJson, runtime) || cliFeedJson.tags[getFeedRuntime(runtime)].release;
this.properties.latestVersion = latestRelease;
if (templatesVersion !== latestRelease) {
ext.outputChannel.show();
ext.outputChannel.appendLine(localize('updatingTemplates', 'Updating .NET templates for Azure Functions...'));
if (templatesInstalled) {
await uninstallTemplates();
}
const tempFolder: string = path.join(os.tmpdir(), fsUtil.getRandomHexString());
await fse.ensureDir(tempFolder);
try {
ext.outputChannel.appendLine(localize('installFuncProject', 'Installing "{0}"', projectPackageId));
const projectTemplatePath: string = path.join(tempFolder, `${projectPackageId}.nupkg`);
await fsUtil.downloadFile(cliFeedJson.releases[latestRelease].projectTemplates, projectTemplatePath);
await cpUtils.executeCommand(undefined, undefined, 'dotnet', 'new', '--install', projectTemplatePath);
ext.outputChannel.appendLine(localize('installFuncs', 'Installing "{0}"', functionsPackageId));
const functionsTemplatePath: string = path.join(tempFolder, `${functionsPackageId}.nupkg`);
await fsUtil.downloadFile(cliFeedJson.releases[latestRelease].itemTemplates, functionsTemplatePath);
await cpUtils.executeCommand(undefined, undefined, 'dotnet', 'new', '--install', functionsTemplatePath);
ext.context.globalState.update(templatesKey, latestRelease);
} finally {
await fse.remove(tempFolder);
}
}
});
await cpUtils.executeCommand(undefined, undefined, 'dotnet', '--version');
} catch (error) {
if (templatesInstalled) {
// If the user already has some version of the templates installed, ignore errors and let them continue
return;
} else {
throw error;
}
throw new Error(localize('dotnetNotInstalled', 'You must have the .NET CLI installed to perform this operation.'));
}
}
export async function uninstallTemplates(): Promise<void> {
await validateDotnetInstalled();
ext.outputChannel.show();
ext.outputChannel.appendLine(localize('uninstallFuncProject', 'Uninstalling "{0}"', projectPackageId));
await cpUtils.executeCommand(undefined, undefined, 'dotnet', 'new', '--uninstall', projectPackageId);
ext.outputChannel.appendLine(localize('uninstallFuncs', 'Uninstalling "{0}"', functionsPackageId));
await cpUtils.executeCommand(undefined, undefined, 'dotnet', 'new', '--uninstall', functionsPackageId);
ext.outputChannel.appendLine(localize('finishedUninstallingTemplates', 'Finished uninstalling Azure Functions templates.'));
ext.context.globalState.update(templatesKey, undefined);
}
}

Просмотреть файл

@ -108,6 +108,7 @@ export async function downloadFile(url: string, filePath: string): Promise<void>
uri: url
};
await fse.ensureDir(path.dirname(filePath));
request(templateOptions, (err: Error) => {
// tslint:disable-next-line:strict-boolean-expressions
if (err) {

Просмотреть файл

@ -9,6 +9,7 @@
// tslint:disable:typedef
// tslint:disable:strict-boolean-expressions
import * as path from 'path';
import { ExtensionContext, Memento } from 'vscode';
class TestMemento implements Memento {
@ -31,7 +32,7 @@ export class TestExtensionContext implements ExtensionContext {
constructor() {
this.globalState = new TestMemento();
}
public asAbsolutePath(_relativePath: string): string {
throw new Error('Method not implemented.');
public asAbsolutePath(relativePath: string): string {
return path.join(__dirname, '..', '..', relativePath);
}
}

Просмотреть файл

@ -14,18 +14,18 @@ import { createFunction } from '../../src/commands/createFunction/createFunction
import { ProjectLanguage, projectLanguageSetting, ProjectRuntime, projectRuntimeSetting, TemplateFilter, templateFilterSetting } from '../../src/constants';
import { ext } from '../../src/extensionVariables';
import { getGlobalFuncExtensionSetting, updateGlobalSetting } from '../../src/ProjectSettings';
import { getTemplateData, TemplateData } from '../../src/templates/TemplateData';
import { FunctionTemplates, getFunctionTemplates } from '../../src/templates/FunctionTemplates';
import * as fsUtil from '../../src/utils/fs';
let backupTemplateData: TemplateData;
let funcPortalTemplateData: TemplateData | undefined;
let backupTemplates: FunctionTemplates;
let latestTemplates: FunctionTemplates | undefined;
// tslint:disable-next-line:no-function-expression
suiteSetup(async function (this: IHookCallbackContext): Promise<void> {
this.timeout(30 * 1000);
// Ensure template data is initialized before any 'Create Function' test is run
backupTemplateData = <TemplateData>(await getTemplateData(undefined));
funcPortalTemplateData = <TemplateData>(await getTemplateData(undefined));
// Ensure templates are initialized before any 'Create Function' test is run
backupTemplates = <FunctionTemplates>(await getFunctionTemplates());
latestTemplates = <FunctionTemplates>(await getFunctionTemplates());
// https://github.com/Microsoft/vscode-azurefunctions/issues/334
});
@ -76,13 +76,13 @@ export abstract class FunctionTesterBase implements vscode.Disposable {
}
public async testCreateFunction(templateName: string, ...inputs: (string | undefined)[]): Promise<void> {
if (funcPortalTemplateData) {
await this.testCreateFunctionInternal(funcPortalTemplateData, this.funcPortalTestFolder, templateName, inputs.slice());
if (latestTemplates) {
await this.testCreateFunctionInternal(latestTemplates, this.funcPortalTestFolder, templateName, inputs.slice());
} else {
assert.fail('Failed to find templates from functions portal.');
}
await this.testCreateFunctionInternal(backupTemplateData, this.backupTestFolder, templateName, inputs.slice());
await this.testCreateFunctionInternal(backupTemplates, this.backupTestFolder, templateName, inputs.slice());
}
public abstract async validateFunction(testFolder: string, funcName: string): Promise<void>;
@ -97,7 +97,7 @@ export abstract class FunctionTesterBase implements vscode.Disposable {
]);
}
private async testCreateFunctionInternal(templateData: TemplateData, testFolder: string, templateName: string, inputs: (string | undefined)[]): Promise<void> {
private async testCreateFunctionInternal(templates: FunctionTemplates, testFolder: string, templateName: string, inputs: (string | undefined)[]): Promise<void> {
// Setup common inputs
const funcName: string = templateName.replace(/ /g, '');
inputs.unshift(funcName); // Specify the function name
@ -108,7 +108,7 @@ export abstract class FunctionTesterBase implements vscode.Disposable {
}
ext.ui = new TestUserInput(inputs);
ext.templateData = templateData;
ext.functionTemplates = templates;
await createFunction(<IActionContext>{ properties: {}, measurements: {} });
assert.equal(inputs.length, 0, 'Not all inputs were used.');

Просмотреть файл

@ -9,7 +9,6 @@ import { IHookCallbackContext, ISuiteCallbackContext } from 'mocha';
import * as path from 'path';
import * as vscode from 'vscode';
import { ProjectLanguage, ProjectRuntime } from '../../src/constants';
import { dotnetUtils } from '../../src/utils/dotnetUtils';
import { FunctionTesterBase } from './FunctionTesterBase';
class CSharpFunctionTester extends FunctionTesterBase {
@ -31,7 +30,6 @@ suite('Create C# Function Tests', async function (this: ISuiteCallbackContext):
suiteSetup(async function (this: IHookCallbackContext): Promise<void> {
this.timeout(120 * 1000);
await csTester.initAsync();
await dotnetUtils.validateTemplatesInstalled();
});
// tslint:disable-next-line:no-function-expression
@ -40,7 +38,7 @@ suite('Create C# Function Tests', async function (this: ISuiteCallbackContext):
await csTester.dispose();
});
const blobTrigger: string = 'Blob trigger';
const blobTrigger: string = 'BlobTrigger';
test(blobTrigger, async () => {
await csTester.testCreateFunction(
blobTrigger,
@ -50,7 +48,7 @@ suite('Create C# Function Tests', async function (this: ISuiteCallbackContext):
);
});
const httpTrigger: string = 'HTTP trigger';
const httpTrigger: string = 'HttpTrigger';
test(httpTrigger, async () => {
await csTester.testCreateFunction(
httpTrigger,
@ -59,7 +57,7 @@ suite('Create C# Function Tests', async function (this: ISuiteCallbackContext):
);
});
const queueTrigger: string = 'Queue trigger';
const queueTrigger: string = 'QueueTrigger';
test(queueTrigger, async () => {
await csTester.testCreateFunction(
queueTrigger,
@ -69,7 +67,7 @@ suite('Create C# Function Tests', async function (this: ISuiteCallbackContext):
);
});
const timerTrigger: string = 'Timer trigger';
const timerTrigger: string = 'TimerTrigger';
test(timerTrigger, async () => {
await csTester.testCreateFunction(
timerTrigger,
@ -79,11 +77,13 @@ suite('Create C# Function Tests', async function (this: ISuiteCallbackContext):
});
test('createFunction API', async () => {
const templateId: string = 'HttpTrigger-CSharp';
// Intentionally testing IoTHub trigger since a partner team plans to use that
const templateId: string = 'Azure.Function.CSharp.IotHubTrigger.2.x';
const functionName: string = 'createFunctionApi';
const namespace: string = 'Company.Function';
const authLevel: string = 'Anonymous';
await vscode.commands.executeCommand('azureFunctions.createFunction', csTester.funcPortalTestFolder, templateId, functionName, { namespace, authLevel });
const iotPath: string = 'messages/events';
const connection: string = 'IoTHub_Setting';
await vscode.commands.executeCommand('azureFunctions.createFunction', csTester.funcPortalTestFolder, templateId, functionName, { namespace: namespace, Path: iotPath, Connection: connection });
await csTester.validateFunction(csTester.funcPortalTestFolder, functionName);
});
});

Просмотреть файл

@ -14,7 +14,6 @@ import { createNewProject } from '../src/commands/createNewProject/createNewProj
import { ProjectLanguage } from '../src/constants';
import { ext } from '../src/extensionVariables';
import { funcToolsInstalled } from '../src/funcCoreTools/validateFuncCoreToolsInstalled';
import { dotnetUtils } from '../src/utils/dotnetUtils';
import * as fsUtil from '../src/utils/fs';
import { validateVSCodeProjectFiles } from './initProjectForVSCode.test';
@ -30,7 +29,6 @@ suite('Create New Project Tests', async function (this: ISuiteCallbackContext):
suiteSetup(async function (this: IHookCallbackContext): Promise<void> {
this.timeout(120 * 1000);
await fse.ensureDir(testFolderPath);
await dotnetUtils.validateTemplatesInstalled();
});
suiteTeardown(async () => {

Просмотреть файл

@ -6,44 +6,46 @@
import * as assert from 'assert';
import { IHookCallbackContext } from 'mocha';
import { JavaProjectCreator } from '../src/commands/createNewProject/JavaProjectCreator';
import { JavaScriptProjectCreator } from '../src/commands/createNewProject/JavaScriptProjectCreator';
import { ProjectLanguage, ProjectRuntime, TemplateFilter } from '../src/constants';
import { Template } from '../src/templates/Template';
import { getTemplateData, TemplateData } from '../src/templates/TemplateData';
import { FunctionTemplates, getFunctionTemplates } from '../src/templates/FunctionTemplates';
import { IFunctionTemplate } from '../src/templates/IFunctionTemplate';
let backupTemplateData: TemplateData;
let funcPortalTemplateData: TemplateData | undefined;
let backupTemplates: FunctionTemplates;
let latestTemplates: FunctionTemplates | undefined;
// tslint:disable-next-line:no-function-expression
suiteSetup(async function (this: IHookCallbackContext): Promise<void> {
this.timeout(30 * 1000);
backupTemplateData = <TemplateData>(await getTemplateData(undefined));
funcPortalTemplateData = <TemplateData>(await getTemplateData(undefined));
backupTemplates = <FunctionTemplates>(await getFunctionTemplates());
latestTemplates = <FunctionTemplates>(await getFunctionTemplates());
// https://github.com/Microsoft/vscode-azurefunctions/issues/334
});
suite('Template Data Tests', async () => {
suite('Template Count Tests', async () => {
test('Valid templates count', async () => {
if (funcPortalTemplateData) {
await validateTemplateData(funcPortalTemplateData);
if (latestTemplates) {
await validateTemplateCounts(latestTemplates);
} else {
assert.fail('Failed to find templates from functions portal.');
}
await validateTemplateData(backupTemplateData);
await validateTemplateCounts(backupTemplates);
});
});
async function validateTemplateData(templateData: TemplateData): Promise<void> {
const jsTemplates: Template[] = await templateData.getTemplates(ProjectLanguage.JavaScript, JavaScriptProjectCreator.defaultRuntime, TemplateFilter.Verified);
assert.equal(jsTemplates.length, 8, 'Unexpected JavaScript templates count.');
async function validateTemplateCounts(templates: FunctionTemplates): Promise<void> {
const jsTemplatesv1: IFunctionTemplate[] = await templates.getTemplates(ProjectLanguage.JavaScript, ProjectRuntime.one, TemplateFilter.Verified);
assert.equal(jsTemplatesv1.length, 8, 'Unexpected JavaScript v1 templates count.');
const javaTemplates: Template[] = await templateData.getTemplates(ProjectLanguage.Java, JavaProjectCreator.defaultRuntime, TemplateFilter.Verified);
const jsTemplatesv2: IFunctionTemplate[] = await templates.getTemplates(ProjectLanguage.JavaScript, ProjectRuntime.beta, TemplateFilter.Verified);
assert.equal(jsTemplatesv2.length, 4, 'Unexpected JavaScript v2 templates count.');
const javaTemplates: IFunctionTemplate[] = await templates.getTemplates(ProjectLanguage.Java, JavaProjectCreator.defaultRuntime, TemplateFilter.Verified);
assert.equal(javaTemplates.length, 4, 'Unexpected Java templates count.');
const cSharpTemplates: Template[] = await templateData.getTemplates(ProjectLanguage.CSharp, ProjectRuntime.one, TemplateFilter.Verified);
const cSharpTemplates: IFunctionTemplate[] = await templates.getTemplates(ProjectLanguage.CSharp, ProjectRuntime.one, TemplateFilter.Verified);
assert.equal(cSharpTemplates.length, 4, 'Unexpected CSharp (.NET Framework) templates count.');
const cSharpTemplatesv2: Template[] = await templateData.getTemplates(ProjectLanguage.CSharp, ProjectRuntime.beta, TemplateFilter.Verified);
const cSharpTemplatesv2: IFunctionTemplate[] = await templates.getTemplates(ProjectLanguage.CSharp, ProjectRuntime.beta, TemplateFilter.Verified);
assert.equal(cSharpTemplatesv2.length, 4, 'Unexpected CSharp (.NET Core) templates count.');
}