Browse Source

Start finding func rather than downloading it (#587)

pull/595/head
Justin Kotalik 6 years ago
committed by GitHub
parent
commit
f1920e3100
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      docs/recipes/azure_functions.md
  2. 7
      docs/reference/azure_function.md
  3. 8
      docs/reference/schema.md
  4. 6
      samples/azure-functions/frontend-backend/README.md
  5. 0
      samples/azure-functions/frontend-backend/backend/.gitignore
  6. 38
      samples/azure-functions/frontend-backend/backend/backend.cs
  7. 18
      samples/azure-functions/frontend-backend/backend/backend.csproj
  8. 0
      samples/azure-functions/frontend-backend/backend/host.json
  9. 24
      samples/azure-functions/frontend-backend/frontend/Program.cs
  10. 27
      samples/azure-functions/frontend-backend/frontend/Properties/launchSettings.json
  11. 87
      samples/azure-functions/frontend-backend/frontend/Startup.cs
  12. 9
      samples/azure-functions/frontend-backend/frontend/appsettings.Development.json
  13. 0
      samples/azure-functions/frontend-backend/frontend/appsettings.json
  14. 12
      samples/azure-functions/frontend-backend/frontend/frontend.csproj
  15. 8
      samples/azure-functions/frontend-backend/tye.yaml
  16. 21
      samples/azure-functions/ingress.yml
  17. 6
      samples/azure-functions/typescript/HttpExample/.funcignore
  18. 43
      samples/azure-functions/typescript/HttpExample/.gitignore
  19. 20
      samples/azure-functions/typescript/HttpExample/HttpExample/function.json
  20. 17
      samples/azure-functions/typescript/HttpExample/HttpExample/index.ts
  21. 15
      samples/azure-functions/typescript/HttpExample/host.json
  22. 501
      samples/azure-functions/typescript/HttpExample/package-lock.json
  23. 19
      samples/azure-functions/typescript/HttpExample/package.json
  24. 10
      samples/azure-functions/typescript/HttpExample/tsconfig.json
  25. 8
      samples/azure-functions/typescript/README.md
  26. 3
      samples/azure-functions/typescript/tye.yaml
  27. 0
      samples/azure-functions/voting/.editorconfig
  28. 0
      samples/azure-functions/voting/README.md
  29. 0
      samples/azure-functions/voting/results/App.razor
  30. 0
      samples/azure-functions/voting/results/Data/VotingResults.cs
  31. 0
      samples/azure-functions/voting/results/Pages/Error.razor
  32. 0
      samples/azure-functions/voting/results/Pages/Index.razor
  33. 0
      samples/azure-functions/voting/results/Pages/_Host.cshtml
  34. 0
      samples/azure-functions/voting/results/Program.cs
  35. 0
      samples/azure-functions/voting/results/Properties/launchSettings.json
  36. 0
      samples/azure-functions/voting/results/Shared/MainLayout.razor
  37. 0
      samples/azure-functions/voting/results/Startup.cs
  38. 0
      samples/azure-functions/voting/results/_Imports.razor
  39. 0
      samples/azure-functions/voting/results/appsettings.Development.json
  40. 10
      samples/azure-functions/voting/results/appsettings.json
  41. 0
      samples/azure-functions/voting/results/results.csproj
  42. 0
      samples/azure-functions/voting/results/wwwroot/css/bootstrap/bootstrap.min.css
  43. 0
      samples/azure-functions/voting/results/wwwroot/css/bootstrap/bootstrap.min.css.map
  44. 0
      samples/azure-functions/voting/results/wwwroot/css/open-iconic/FONT-LICENSE
  45. 0
      samples/azure-functions/voting/results/wwwroot/css/open-iconic/ICON-LICENSE
  46. 0
      samples/azure-functions/voting/results/wwwroot/css/open-iconic/README.md
  47. 0
      samples/azure-functions/voting/results/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css
  48. 0
      samples/azure-functions/voting/results/wwwroot/css/open-iconic/font/fonts/open-iconic.eot
  49. 0
      samples/azure-functions/voting/results/wwwroot/css/open-iconic/font/fonts/open-iconic.otf
  50. 0
      samples/azure-functions/voting/results/wwwroot/css/open-iconic/font/fonts/open-iconic.svg
  51. 0
      samples/azure-functions/voting/results/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf
  52. 0
      samples/azure-functions/voting/results/wwwroot/css/open-iconic/font/fonts/open-iconic.woff
  53. 0
      samples/azure-functions/voting/results/wwwroot/css/site.css
  54. 0
      samples/azure-functions/voting/results/wwwroot/favicon.ico
  55. 0
      samples/azure-functions/voting/tye.yaml
  56. 0
      samples/azure-functions/voting/vote/Pages/Index.cshtml
  57. 0
      samples/azure-functions/voting/vote/Pages/Index.cshtml.cs
  58. 0
      samples/azure-functions/voting/vote/Pages/_ViewImports.cshtml
  59. 0
      samples/azure-functions/voting/vote/Program.cs
  60. 0
      samples/azure-functions/voting/vote/Properties/launchSettings.json
  61. 0
      samples/azure-functions/voting/vote/Startup.cs
  62. 0
      samples/azure-functions/voting/vote/appsettings.Development.json
  63. 0
      samples/azure-functions/voting/vote/appsettings.json
  64. 0
      samples/azure-functions/voting/vote/vote.csproj
  65. 0
      samples/azure-functions/voting/vote/wwwroot/favicon.ico
  66. 0
      samples/azure-functions/voting/vote/wwwroot/site.css
  67. 264
      samples/azure-functions/voting/worker-function/.gitignore
  68. 0
      samples/azure-functions/voting/worker-function/Dockerfile
  69. 0
      samples/azure-functions/voting/worker-function/GetResults.cs
  70. 0
      samples/azure-functions/voting/worker-function/QueueTrigger.cs
  71. 0
      samples/azure-functions/voting/worker-function/Startup.cs
  72. 11
      samples/azure-functions/voting/worker-function/host.json
  73. 0
      samples/azure-functions/voting/worker-function/worker-function.csproj
  74. 7
      samples/azure-functions/worker-function/local.settings.json
  75. 2
      src/Microsoft.Tye.Core/ApplicationFactory.cs
  76. 2
      src/Microsoft.Tye.Core/AzureFunctionServiceBuilder.cs
  77. 260
      src/Microsoft.Tye.Core/FuncDetector.cs
  78. 3
      src/Microsoft.Tye.Core/Serialization/ConfigServiceParser.cs
  79. 54
      src/Microsoft.Tye.Hosting/FuncDownloader.cs
  80. 79
      src/Microsoft.Tye.Hosting/FuncFinder.cs
  81. 5
      src/Microsoft.Tye.Hosting/Model/AzureFunctionRunInfo.cs
  82. 7
      src/Microsoft.Tye.Hosting/ProcessRunner.cs
  83. 2
      src/Microsoft.Tye.Hosting/TyeHost.cs
  84. 17
      src/schema/tye-schema.json
  85. 18
      test/E2ETest/TyeRunTests.cs
  86. 1
      test/E2ETest/testassets/projects/azure-functions/tye.yaml
  87. 68
      test/UnitTests/FuncFinderTests.cs

8
docs/recipes/azure_functions.md

@ -11,6 +11,14 @@ To start, create an Azure Function project in a folder called `backend-function`
- [Visual Studio](https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-your-first-function-visual-studio)
- [Commandline](https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-azure-function-azure-cli?tabs=bash%2Cbrowser&pivots=programming-language-csharp)
Next, you must have the [Azure Functions Core Tools](https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=windows%2Ccsharp%2Cbash) through npm. By default, if you created an azure function through VSCode or Commandline, you will already have installed it. Otherwise, you can install the core tools by running:
```bash
npm install -g azure-functions-core-tools@3
```
You can also specify a path to func by specifying `pathToFunc` for the azure function service.
Next, create an HttpTrigger called `MyHttpTrigger` in your functions project. Change the contents of MyHttpTrigger to the following:
```c#

7
docs/reference/azure_function.md

@ -1,7 +0,0 @@
# Azure function support details in Tye
- supports v2 and v3 functions
- Specify v2 or v3 in tye.yaml
- Specify x64 or x86 in tye.yaml (defaults to x64)
- Specify another path to func.exe

8
docs/reference/schema.md

@ -216,6 +216,14 @@ A path to another tye.yaml to be used by the application.
A reference to a repository that will be cloned and used by the application. By default, it is a string that would be passed after `git clone`.
#### `azureFunction` (string)
A path to a folder which contains an azure function project.
#### `pathToFunc` (string)
An optional path to the Azure Functions host to be used instead of the default one installed by npm.
## Environment Variables
`EnvironmentVariable` elements appear in a list inside the `env` property of a `Service`.

6
samples/azure-functions/frontend-backend/README.md

@ -0,0 +1,6 @@
# Frontend-backend example
A simple example showing a frontend and backend function app.
## For running
Simply execute `tye run` and navigate to the frontend. You should see a response with information from the frontend and backend.

0
samples/azure-functions/worker-function/.gitignore → samples/azure-functions/frontend-backend/backend/.gitignore

38
samples/azure-functions/frontend-backend/backend/backend.cs

@ -0,0 +1,38 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace backend
{
public static class backend
{
[FunctionName("backend")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
var backendInfo = new BackendInfo()
{
IP = req.HttpContext.Connection.LocalIpAddress.ToString(),
Hostname = System.Net.Dns.GetHostName(),
};
return new OkObjectResult(backendInfo);
}
class BackendInfo
{
public string IP { get; set; } = default!;
public string Hostname { get; set; } = default!;
}
}
}

18
samples/azure-functions/frontend-backend/backend/backend.csproj

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.3" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>

0
samples/azure-functions/worker-function/host.json → samples/azure-functions/frontend-backend/backend/host.json

24
samples/azure-functions/frontend-backend/frontend/Program.cs

@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace Frontend
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}

27
samples/azure-functions/frontend-backend/frontend/Properties/launchSettings.json

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:16377",
"sslPort": 44392
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"frontend": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

87
samples/azure-functions/frontend-backend/frontend/Startup.cs

@ -0,0 +1,87 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Frontend
{
public class Startup
{
private readonly JsonSerializerOptions options = new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
var uri = Configuration.GetServiceUri("backend")!;
logger.LogInformation("Backend URL: {BackendUrl}", uri);
var httpClient = new HttpClient()
{
BaseAddress = uri
};
endpoints.MapGet("/", async context =>
{
var bytes = await httpClient.GetByteArrayAsync("/api/backend");
var backendInfo = JsonSerializer.Deserialize<BackendInfo>(bytes, options);
await context.Response.WriteAsync($"Frontend Listening IP: {context.Connection.LocalIpAddress}{Environment.NewLine}");
await context.Response.WriteAsync($"Frontend Hostname: {Dns.GetHostName()}{Environment.NewLine}");
await context.Response.WriteAsync($"EnvVar Configuration value: {Configuration["App:Value"]}{Environment.NewLine}");
await context.Response.WriteAsync($"Backend Listening IP: {backendInfo.IP}{Environment.NewLine}");
await context.Response.WriteAsync($"Backend Hostname: {backendInfo.Hostname}{Environment.NewLine}");
var addresses = await Dns.GetHostAddressesAsync(uri.Host);
await context.Response.WriteAsync($"Backend Host Addresses: {string.Join(", ", addresses.Select(a => a.ToString()))}");
});
endpoints.MapHealthChecks("/healthz");
});
}
class BackendInfo
{
public string IP { get; set; } = default!;
public string Hostname { get; set; } = default!;
}
}
}

9
samples/azure-functions/frontend-backend/frontend/appsettings.Development.json

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

0
samples/azure-functions/results/appsettings.json → samples/azure-functions/frontend-backend/frontend/appsettings.json

12
samples/azure-functions/frontend-backend/frontend/frontend.csproj

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>Frontend</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="$(TyeLibrariesPath)\Microsoft.Tye.Extensions.Configuration\Microsoft.Tye.Extensions.Configuration.csproj" />
</ItemGroup>
</Project>

8
samples/azure-functions/frontend-backend/tye.yaml

@ -0,0 +1,8 @@
# tye application configuration file
# read all about it at https://github.com/dotnet/tye
name: frontend-backend
services:
- name: backend
azureFunction: backend/
- name: frontend
project: frontend/frontend.csproj

21
samples/azure-functions/ingress.yml

@ -1,21 +0,0 @@
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-basic
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- http:
paths:
- backend:
serviceName: vote
servicePort: 80
path: /vote(/|$)(.*)
- backend:
serviceName: results
servicePort: 80
path: /results(/|$)(.*)

6
samples/azure-functions/typescript/HttpExample/.funcignore

@ -0,0 +1,6 @@
*.js.map
*.ts
.git*
.vscode
local.settings.json
test

43
samples/azure-functions/typescript/HttpExample/.gitignore

@ -0,0 +1,43 @@
bin
obj
csx
.vs
edge
Publish
*.user
*.suo
*.cscfg
*.Cache
project.lock.json
/packages
/TestResults
/tools/NuGet.exe
/App_Data
/secrets
/data
.secrets
appsettings.json
local.settings.json
node_modules
dist
# Local python packages
.python_packages/
# Python Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

20
samples/azure-functions/typescript/HttpExample/HttpExample/function.json

@ -0,0 +1,20 @@
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
],
"scriptFile": "../dist/HttpExample/index.js"
}

17
samples/azure-functions/typescript/HttpExample/HttpExample/index.ts

@ -0,0 +1,17 @@
import { AzureFunction, Context, HttpRequest } from "@azure/functions"
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
context.log('HTTP trigger function processed a requests.');
const name = (req.query.name || (req.body && req.body.name));
const responseMessage = name
? "Hello, " + name + ". This HTTP triggered function executed successfully."
: "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.";
context.res = {
// status: 200, /* Defaults to 200 */
body: responseMessage
};
};
export default httpTrigger;

15
samples/azure-functions/typescript/HttpExample/host.json

@ -0,0 +1,15 @@
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}

501
samples/azure-functions/typescript/HttpExample/package-lock.json

@ -0,0 +1,501 @@
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"@azure/functions": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@azure/functions/-/functions-1.2.2.tgz",
"integrity": "sha512-p/dDHq1sG/iAib+eDY4NxskWHoHW1WFzD85s0SfWxc2wVjJbxB0xz/zBF4s7ymjVgTu+0ceipeBk+tmpnt98oA==",
"dev": true
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"dev": true,
"requires": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
"dev": true,
"requires": {
"object-keys": "^1.0.12"
}
},
"error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"dev": true,
"requires": {
"is-arrayish": "^0.2.1"
}
},
"es-abstract": {
"version": "1.17.6",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.2.0",
"is-regex": "^1.1.0",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimend": "^1.0.1",
"string.prototype.trimstart": "^1.0.1"
}
},
"es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
"integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
"dev": true,
"requires": {
"is-callable": "^1.1.4",
"is-date-object": "^1.0.1",
"is-symbol": "^1.0.2"
}
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"graceful-fs": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
"dev": true
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"requires": {
"function-bind": "^1.1.1"
}
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
},
"has-symbols": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
"dev": true
},
"hosted-git-info": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
"dev": true
},
"is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
"dev": true
},
"is-callable": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz",
"integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==",
"dev": true
},
"is-date-object": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
"integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
"dev": true
},
"is-regex": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz",
"integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==",
"dev": true,
"requires": {
"has-symbols": "^1.0.1"
}
},
"is-symbol": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
"integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
"dev": true,
"requires": {
"has-symbols": "^1.0.1"
}
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"json-parse-better-errors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
"dev": true
},
"load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
"integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"parse-json": "^4.0.0",
"pify": "^3.0.0",
"strip-bom": "^3.0.0"
}
},
"memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
"integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
"dev": true
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
"integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
"dev": true,
"requires": {
"hosted-git-info": "^2.1.4",
"resolve": "^1.10.0",
"semver": "2 || 3 || 4 || 5",
"validate-npm-package-license": "^3.0.1"
}
},
"npm-run-all": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
"integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"chalk": "^2.4.1",
"cross-spawn": "^6.0.5",
"memorystream": "^0.3.1",
"minimatch": "^3.0.4",
"pidtree": "^0.3.0",
"read-pkg": "^3.0.0",
"shell-quote": "^1.6.1",
"string.prototype.padend": "^3.0.0"
}
},
"object-inspect": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
"integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
"dev": true
},
"object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"dev": true
},
"object.assign": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
"integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"function-bind": "^1.1.1",
"has-symbols": "^1.0.0",
"object-keys": "^1.0.11"
}
},
"parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
"dev": true,
"requires": {
"error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
}
},
"path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
"dev": true
},
"path-parse": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"dev": true
},
"path-type": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
"dev": true,
"requires": {
"pify": "^3.0.0"
}
},
"pidtree": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz",
"integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==",
"dev": true
},
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true
},
"read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
"integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
"dev": true,
"requires": {
"load-json-file": "^4.0.0",
"normalize-package-data": "^2.3.2",
"path-type": "^3.0.0"
}
},
"resolve": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
"integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
"dev": true,
"requires": {
"path-parse": "^1.0.6"
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"dev": true,
"requires": {
"shebang-regex": "^1.0.0"
}
},
"shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true
},
"shell-quote": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz",
"integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==",
"dev": true
},
"spdx-correct": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
"integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
"dev": true,
"requires": {
"spdx-expression-parse": "^3.0.0",
"spdx-license-ids": "^3.0.0"
}
},
"spdx-exceptions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
"integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
"dev": true
},
"spdx-expression-parse": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
"dev": true,
"requires": {
"spdx-exceptions": "^2.1.0",
"spdx-license-ids": "^3.0.0"
}
},
"spdx-license-ids": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
"integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
"dev": true
},
"string.prototype.padend": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz",
"integrity": "sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.0-next.1"
}
},
"string.prototype.trimend": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz",
"integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5"
}
},
"string.prototype.trimstart": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
"integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5"
}
},
"strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
"dev": true
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
},
"typescript": {
"version": "3.9.6",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.6.tgz",
"integrity": "sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==",
"dev": true
},
"validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
"dev": true,
"requires": {
"spdx-correct": "^3.0.0",
"spdx-expression-parse": "^3.0.0"
}
},
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
}
}
}
}

19
samples/azure-functions/typescript/HttpExample/package.json

@ -0,0 +1,19 @@
{
"name": "",
"version": "",
"scripts": {
"build": "tsc",
"build:production": "npm run prestart && npm prune --production",
"watch": "tsc --w",
"prestart": "npm run build && func extensions install",
"start:host": "func start",
"start": "npm-run-all --parallel start:host watch",
"test": "echo \"No tests yet...\""
},
"description": "",
"devDependencies": {
"@azure/functions": "^1.0.1-beta1",
"npm-run-all": "^4.1.5",
"typescript": "^3.3.3"
}
}

10
samples/azure-functions/typescript/HttpExample/tsconfig.json

@ -0,0 +1,10 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "dist",
"rootDir": ".",
"sourceMap": true,
"strict": false
}
}

8
samples/azure-functions/typescript/README.md

@ -0,0 +1,8 @@
# Typescript example
A simple example showing that tye supports running non-dotnet azure functions locally.
## For running
Before running, navigate to the HttpExample and run `npm install`. Run `npm start` as well to verify the function starts without tye.
Next, all you need to do is execute `tye run` and navigate to the dashboard. Navigate to <SERVICE_URL>/api/HttpExample to see the function working.

3
samples/azure-functions/typescript/tye.yaml

@ -0,0 +1,3 @@
services:
- name: HttpExample
azureFunction: HttpExample/

0
samples/azure-functions/.editorconfig → samples/azure-functions/voting/.editorconfig

0
samples/azure-functions/README.md → samples/azure-functions/voting/README.md

0
samples/azure-functions/results/App.razor → samples/azure-functions/voting/results/App.razor

0
samples/azure-functions/results/Data/VotingResults.cs → samples/azure-functions/voting/results/Data/VotingResults.cs

0
samples/azure-functions/results/Pages/Error.razor → samples/azure-functions/voting/results/Pages/Error.razor

0
samples/azure-functions/results/Pages/Index.razor → samples/azure-functions/voting/results/Pages/Index.razor

0
samples/azure-functions/results/Pages/_Host.cshtml → samples/azure-functions/voting/results/Pages/_Host.cshtml

0
samples/azure-functions/results/Program.cs → samples/azure-functions/voting/results/Program.cs

0
samples/azure-functions/results/Properties/launchSettings.json → samples/azure-functions/voting/results/Properties/launchSettings.json

0
samples/azure-functions/results/Shared/MainLayout.razor → samples/azure-functions/voting/results/Shared/MainLayout.razor

0
samples/azure-functions/results/Startup.cs → samples/azure-functions/voting/results/Startup.cs

0
samples/azure-functions/results/_Imports.razor → samples/azure-functions/voting/results/_Imports.razor

0
samples/azure-functions/results/appsettings.Development.json → samples/azure-functions/voting/results/appsettings.Development.json

10
samples/azure-functions/voting/results/appsettings.json

@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

0
samples/azure-functions/results/results.csproj → samples/azure-functions/voting/results/results.csproj

0
samples/azure-functions/results/wwwroot/css/bootstrap/bootstrap.min.css → samples/azure-functions/voting/results/wwwroot/css/bootstrap/bootstrap.min.css

0
samples/azure-functions/results/wwwroot/css/bootstrap/bootstrap.min.css.map → samples/azure-functions/voting/results/wwwroot/css/bootstrap/bootstrap.min.css.map

0
samples/azure-functions/results/wwwroot/css/open-iconic/FONT-LICENSE → samples/azure-functions/voting/results/wwwroot/css/open-iconic/FONT-LICENSE

0
samples/azure-functions/results/wwwroot/css/open-iconic/ICON-LICENSE → samples/azure-functions/voting/results/wwwroot/css/open-iconic/ICON-LICENSE

0
samples/azure-functions/results/wwwroot/css/open-iconic/README.md → samples/azure-functions/voting/results/wwwroot/css/open-iconic/README.md

0
samples/azure-functions/results/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css → samples/azure-functions/voting/results/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css

0
samples/azure-functions/results/wwwroot/css/open-iconic/font/fonts/open-iconic.eot → samples/azure-functions/voting/results/wwwroot/css/open-iconic/font/fonts/open-iconic.eot

0
samples/azure-functions/results/wwwroot/css/open-iconic/font/fonts/open-iconic.otf → samples/azure-functions/voting/results/wwwroot/css/open-iconic/font/fonts/open-iconic.otf

0
samples/azure-functions/results/wwwroot/css/open-iconic/font/fonts/open-iconic.svg → samples/azure-functions/voting/results/wwwroot/css/open-iconic/font/fonts/open-iconic.svg

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

0
samples/azure-functions/results/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf → samples/azure-functions/voting/results/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf

0
samples/azure-functions/results/wwwroot/css/open-iconic/font/fonts/open-iconic.woff → samples/azure-functions/voting/results/wwwroot/css/open-iconic/font/fonts/open-iconic.woff

0
samples/azure-functions/results/wwwroot/css/site.css → samples/azure-functions/voting/results/wwwroot/css/site.css

0
samples/azure-functions/results/wwwroot/favicon.ico → samples/azure-functions/voting/results/wwwroot/favicon.ico

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

0
samples/azure-functions/tye.yaml → samples/azure-functions/voting/tye.yaml

0
samples/azure-functions/vote/Pages/Index.cshtml → samples/azure-functions/voting/vote/Pages/Index.cshtml

0
samples/azure-functions/vote/Pages/Index.cshtml.cs → samples/azure-functions/voting/vote/Pages/Index.cshtml.cs

0
samples/azure-functions/vote/Pages/_ViewImports.cshtml → samples/azure-functions/voting/vote/Pages/_ViewImports.cshtml

0
samples/azure-functions/vote/Program.cs → samples/azure-functions/voting/vote/Program.cs

0
samples/azure-functions/vote/Properties/launchSettings.json → samples/azure-functions/voting/vote/Properties/launchSettings.json

0
samples/azure-functions/vote/Startup.cs → samples/azure-functions/voting/vote/Startup.cs

0
samples/azure-functions/vote/appsettings.Development.json → samples/azure-functions/voting/vote/appsettings.Development.json

0
samples/azure-functions/vote/appsettings.json → samples/azure-functions/voting/vote/appsettings.json

0
samples/azure-functions/vote/vote.csproj → samples/azure-functions/voting/vote/vote.csproj

0
samples/azure-functions/vote/wwwroot/favicon.ico → samples/azure-functions/voting/vote/wwwroot/favicon.ico

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

0
samples/azure-functions/vote/wwwroot/site.css → samples/azure-functions/voting/vote/wwwroot/site.css

264
samples/azure-functions/voting/worker-function/.gitignore

@ -0,0 +1,264 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# Azure Functions localsettings file
local.settings.json
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
#*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

0
samples/azure-functions/worker-function/Dockerfile → samples/azure-functions/voting/worker-function/Dockerfile

0
samples/azure-functions/worker-function/GetResults.cs → samples/azure-functions/voting/worker-function/GetResults.cs

0
samples/azure-functions/worker-function/QueueTrigger.cs → samples/azure-functions/voting/worker-function/QueueTrigger.cs

0
samples/azure-functions/worker-function/Startup.cs → samples/azure-functions/voting/worker-function/Startup.cs

11
samples/azure-functions/voting/worker-function/host.json

@ -0,0 +1,11 @@
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingExcludedTypes": "Request",
"samplingSettings": {
"isEnabled": true
}
}
}
}

0
samples/azure-functions/worker-function/worker-function.csproj → samples/azure-functions/voting/worker-function/worker-function.csproj

7
samples/azure-functions/worker-function/local.settings.json

@ -1,7 +0,0 @@
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
}
}

2
src/Microsoft.Tye.Core/ApplicationFactory.cs

@ -231,8 +231,6 @@ namespace Microsoft.Tye
{
Args = configService.Args,
Replicas = configService.Replicas ?? 1,
Architecture = configService.Architecture,
Version = configService.Version,
FuncExecutablePath = configService.FuncExecutable
};

2
src/Microsoft.Tye.Core/AzureFunctionServiceBuilder.cs

@ -15,8 +15,6 @@ namespace Microsoft.Tye
public int Replicas { get; set; } = 1;
public string? Args { get; set; }
public string FunctionPath { get; }
public string? Version { get; set; }
public string? Architecture { get; set; }
public string? FuncExecutablePath { get; set; }
}
}

260
src/Microsoft.Tye.Core/FuncDetector.cs

@ -1,260 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Tye
{
public class FuncDetector
{
// Same folder which VS installs azure apps to.
private const string WindowsFuncDownloadLocation = "%LOCALAPPDATA%/AzureFunctionsTools/Tye";
private string _macOSFuncDownloadLocation;
private string _linuxFuncDownloadLocation;
// Default to v3 as it's highly backwards compatible with v2. Diagnostics with v2
// don't work by default as v2 uses 2.2.
private const string DefaultFuncVersion = "v3";
private Dictionary<string, string> _pathsToFunc;
internal FuncDetector()
{
_pathsToFunc = new Dictionary<string, string>();
var baseDirectory = Environment.GetEnvironmentVariable("HOME") ?? Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
_macOSFuncDownloadLocation = Path.Combine(baseDirectory, ".tye/AzureFunctionTools/Tye");
_linuxFuncDownloadLocation = Path.Combine(baseDirectory, ".tye/AzureFunctionTools/Tye");
}
public static FuncDetector Instance { get; } = new FuncDetector();
public async Task<string> PathToFunc(string? version, string? arch, string? downloadPath, ILogger logger, CancellationToken cancellation, bool dryRun = false)
{
version = ValidateAndConvertVersion(version ?? DefaultFuncVersion, logger);
// Default to x64
arch = ValidateArch(arch ?? "x64");
if (!_pathsToFunc.ContainsKey(version))
{
_pathsToFunc[version] = await GetPathToFunc(version, arch, downloadPath, logger, cancellation, dryRun);
}
return _pathsToFunc[version];
}
private string ValidateArch(string arch)
{
switch (arch)
{
case "x64":
return arch;
case "x86":
return arch;
default:
throw new NotSupportedException("Unrecognized architecture for function.");
}
}
/// <summary>
/// Function to convert versions to versions expected.
/// </summary>
/// <param name="version"></param>
/// <returns></returns>
private string ValidateAndConvertVersion(string version, ILogger logger)
{
switch (version)
{
case "2":
case "v2":
return "v2";
case "3":
case "v3":
return "v3";
case "1":
case "v1":
// TODO maybe don't throw here and just log a warning.
logger.LogWarning("Functions V1 are unsupported and untested in Tye. Use at your own risk!");
return "v1";
default:
return version;
}
}
private async Task<string> GetPathToFunc(string version, string arch, string? downloadPath, ILogger logger, CancellationToken cancellation, bool dryRun)
{
var osName = GetOsName();
using var client = new HttpClient();
(var preciseVersion, var uri) = await GetDownloadInfo(version, client, arch, osName, logger, cancellation, dryRun);
var directoryToInstallTo = downloadPath ?? GetAzureFunctionDirectoryWithVersion(preciseVersion);
var funcPath = Path.Combine(directoryToInstallTo, GetFuncName());
if (Directory.Exists(directoryToInstallTo) && File.Exists(funcPath))
{
logger.LogInformation("Using func to {FuncPath}", funcPath);
return funcPath;
}
var response = await client.GetAsync(uri);
if (dryRun)
{
return funcPath;
}
using (var tempFile = TempFile.Create())
{
{
var responseStream = await response.Content.ReadAsStreamAsync();
await using var stream = File.OpenWrite(tempFile.FilePath);
await using var writer = new StreamWriter(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), leaveOpen: true);
await responseStream.CopyToAsync(stream);
}
logger.LogInformation("Installing func to {FuncPath}", directoryToInstallTo);
ZipFile.ExtractToDirectory(tempFile.FilePath, directoryToInstallTo);
// For some reason, func isn't marked as executable via unzipping.
return funcPath;
}
}
private async Task<(string, string)> GetDownloadInfo(string version, HttpClient client, string arch, string os, ILogger logger, CancellationToken cancellation, bool dryRun)
{
var directory = GetAzureFunctionDirectory();
var feedJsonFile = Path.Combine(GetAzureFunctionDirectory(), "feed-v3.json");
JToken json;
if (File.Exists(feedJsonFile) && (DateTime.Now - File.GetLastWriteTimeUtc(feedJsonFile)).TotalDays < 90)
{
logger.LogInformation("Using existing feed file in {FeedJsonFile}", feedJsonFile);
// don't bother rewriting it.
using (JsonTextReader reader = new JsonTextReader(new StreamReader(feedJsonFile)))
{
json = JObject.ReadFrom(reader);
}
}
else
{
// Using VS/VSCode maintained list of function downloads
logger.LogInformation("Retrieving list of azure function versions from internet.");
var response = await client.GetAsync("https://go.microsoft.com/fwlink/?linkid=2109029", cancellation);
var responseString = await response.Content.ReadAsStringAsync();
using (JsonTextReader reader = new JsonTextReader(new StringReader(responseString)))
{
json = JObject.ReadFrom(reader);
}
// Don't write file during dry run.
if (!dryRun)
{
logger.LogInformation("Writing list of azure function versions to {FeedJsonFile}.", feedJsonFile);
Directory.CreateDirectory(new FileInfo(feedJsonFile).DirectoryName!);
await File.WriteAllTextAsync(feedJsonFile, responseString, cancellation);
}
}
// Get the version for the folder
// and the download link for the zip.
var versionInfo = (JValue)json["tags"][version]["release"];
JValue? downloadLink;
if (version == "v1")
{
downloadLink = (JValue)json["releases"][(string)versionInfo]["cli"];
}
else
{
downloadLink = (JValue)json["releases"][(string)versionInfo]["standaloneCli"]
.Where(s => (((string)s["OS"])?.Equals(os) == true || ((string)s["OperatingSystem"])?.Equals(os) == true) && ((string)s["Architecture"]).Equals(arch))
.Single()["downloadLink"];
}
return ((string)versionInfo, (string)downloadLink);
}
public string GetAzureFunctionDirectory()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// Default is min.win for whatever reason, probably minified win
return Environment.ExpandEnvironmentVariables(WindowsFuncDownloadLocation);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return Environment.ExpandEnvironmentVariables(_macOSFuncDownloadLocation);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return Environment.ExpandEnvironmentVariables(_linuxFuncDownloadLocation);
}
else
{
throw new NotSupportedException("OS platform not supported.");
}
}
public string GetAzureFunctionDirectoryWithVersion(string preciseVersion)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// Default is min.win for whatever reason, probably minified win
return Environment.ExpandEnvironmentVariables(Path.Combine(WindowsFuncDownloadLocation, preciseVersion));
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return Environment.ExpandEnvironmentVariables(Path.Combine(_macOSFuncDownloadLocation, preciseVersion));
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return Environment.ExpandEnvironmentVariables(Path.Combine(_linuxFuncDownloadLocation, preciseVersion));
}
else
{
throw new NotSupportedException("OS platform not supported.");
}
}
public static string GetFuncName()
{
return "func.dll";
}
private static string GetOsName()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// Default is min.win for whatever reason, probably minified win
return "Windows";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return "MacOS";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return "Linux";
}
else
{
throw new NotSupportedException("OS platform not supported.");
}
}
}
}

3
src/Microsoft.Tye.Core/Serialization/ConfigServiceParser.cs

@ -149,6 +149,9 @@ namespace Tye.Serialization
case "azureFunction":
service.AzureFunction = YamlParser.GetScalarValue(key, child.Value);
break;
case "pathToFunc":
service.FuncExecutable = YamlParser.GetScalarValue(key, child.Value);
break;
default:
throw new TyeYamlException(child.Key.Start, CoreStrings.FormatUnrecognizedKey(key));
}

54
src/Microsoft.Tye.Hosting/FuncDownloader.cs

@ -1,54 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Tye.Hosting.Model;
namespace Microsoft.Tye.Hosting
{
public class FuncDownloader : IApplicationProcessor
{
private readonly ILogger _logger;
private readonly CancellationTokenSource _cancellationTokenSource;
public FuncDownloader(ILogger logger)
{
_logger = logger;
_cancellationTokenSource = new CancellationTokenSource();
}
public async Task StartAsync(Application application)
{
var functions = new HashSet<AzureFunctionRunInfo>();
foreach (var s in application.Services)
{
if (s.Value.Description.RunInfo is AzureFunctionRunInfo function)
{
functions.Add(function);
}
}
// No functions
if (functions.Count == 0)
{
return;
}
foreach (var func in functions)
{
func.FuncExecutablePath ??= await FuncDetector.Instance.PathToFunc(func.Version, func.Architecture, func.DownloadPath, _logger, _cancellationTokenSource.Token);
}
}
public Task StopAsync(Application application)
{
_cancellationTokenSource.Cancel();
return Task.CompletedTask;
}
}
}

79
src/Microsoft.Tye.Hosting/FuncFinder.cs

@ -0,0 +1,79 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Tye.Hosting.Model;
namespace Microsoft.Tye.Hosting
{
public class FuncFinder : IApplicationProcessor
{
private ILogger _logger;
public FuncFinder(ILogger logger)
{
_logger = logger;
}
public Task StartAsync(Application application)
{
var functions = new HashSet<AzureFunctionRunInfo>();
foreach (var s in application.Services)
{
if (s.Value.Description.RunInfo is AzureFunctionRunInfo function)
{
functions.Add(function);
}
}
// No functions
if (functions.Count == 0)
{
return Task.CompletedTask;
}
foreach (var func in functions)
{
func.FuncExecutablePath ??= FindFuncForVersion(func);
}
return Task.CompletedTask;
}
private string? FindFuncForVersion(AzureFunctionRunInfo func)
{
var npmFuncDllPath = GetFuncNpmPath();
if (!File.Exists(npmFuncDllPath))
{
throw new FileNotFoundException("Could not find func installation. Please install the azure function core tools via: `npm install -g azure-functions-core-tools@3`");
}
_logger.LogDebug("Using func for running azure functions located at {Func}.", npmFuncDllPath);
return npmFuncDllPath;
}
private string GetFuncNpmPath()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return Environment.ExpandEnvironmentVariables("%APPDATA%/npm/node_modules/azure-functions-core-tools/bin/func.dll");
}
else
{
return Environment.ExpandEnvironmentVariables("/usr/local/lib/node_modules/azure-functions-core-tools/bin/func.dll");
}
}
public Task StopAsync(Application application)
{
return Task.CompletedTask;
}
}
}

5
src/Microsoft.Tye.Hosting/Model/AzureFunctionRunInfo.cs

@ -12,16 +12,11 @@ namespace Microsoft.Tye.Hosting.Model
{
Args = function.Args;
FunctionPath = function.FunctionPath;
Version = function.Version;
Architecture = function.Architecture;
FuncExecutablePath = function.FuncExecutablePath;
}
public string? Args { get; }
public string FunctionPath { get; }
public string? Version { get; }
public string? Architecture { get; }
public string? FuncExecutablePath { get; set; }
public string? DownloadPath { get; }
}
}

7
src/Microsoft.Tye.Hosting/ProcessRunner.cs

@ -240,13 +240,6 @@ namespace Microsoft.Tye.Hosting
// 3. For non-ASP.NET Core apps, pass the same information in the PORT env variable as a semicolon separated list.
environment["PORT"] = string.Join(";", ports.Select(p => $"{p.Port}"));
environment["HOST__LOCALHTTPPORT"] = string.Join(";", ports.Select(p => $"{p.Port}"));
environment["ASPNETCORE__HOST__LOCALHTTPPORT"] = string.Join(";", ports.Select(p => $"{p.Port}"));
if (service.ServiceType == ServiceType.Function)
{
environment["ASPNETCORE_URLS"] = string.Join(";", ports.Select(p => $"{p.Protocol ?? "http"}://{host}:{p.Port}"));
}
if (service.ServiceType == ServiceType.Function)
{

2
src/Microsoft.Tye.Hosting/TyeHost.cs

@ -287,7 +287,7 @@ namespace Microsoft.Tye.Hosting
new ProxyService(logger),
new HttpProxyService(logger),
new DockerImagePuller(logger),
new FuncDownloader(logger),
new FuncFinder(logger),
new ReplicaMonitor(logger),
new DockerRunner(logger, replicaRegistry),
new ProcessRunner(logger, replicaRegistry, ProcessRunnerOptions.FromHostOptions(options))

17
src/schema/tye-schema.json

@ -200,21 +200,10 @@
"$ref": "#/definitions/binding"
}
},
"arch":
"pathToFunc":
{
},
"version":
{
},
"funcDownloadPath":
{
},
"funcExePath":
{
"description": "Optional path to the function host to be used when launching functions. Can point to either func.dll or the binary.",
"type": "string"
}
},
"required": [

18
test/E2ETest/TyeRunTests.cs

@ -16,6 +16,7 @@ using Microsoft.Tye;
using Microsoft.Tye.Hosting;
using Microsoft.Tye.Hosting.Model;
using Microsoft.Tye.Hosting.Model.V1;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel;
using Test.Infrastructure;
using Xunit;
using Xunit.Abstractions;
@ -75,12 +76,27 @@ namespace E2ETest
});
}
[Fact]
[Fact(Skip = "Need to figure out how to install func before running")]
public async Task FrontendBackendAzureFunctionTest()
{
// Install to directory
using var tmp = TempDirectory.Create();
await ProcessUtil.RunAsync("npm", "install azure-functions-core-tools@3`", workingDirectory: tmp.DirectoryPath);
using var projectDirectory = CopyTestProjectDirectory("azure-functions");
var content = @$"
# tye application configuration file
# read all about it at https://github.com/dotnet/tye
name: frontend-backend
services:
- name: backend
azureFunction: backend/
pathToFunc: {tmp.DirectoryPath}/node_modules/azure-functions-core-tools/bin/func.dll
- name: frontend
project: frontend/frontend.csproj";
var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml"));
await File.WriteAllTextAsync(projectFile.FullName, content);
var outputContext = new OutputContext(_sink, Verbosity.Debug);
var application = await ApplicationFactory.CreateAsync(outputContext, projectFile);

1
test/E2ETest/testassets/projects/azure-functions/tye.yaml

@ -4,5 +4,6 @@ name: frontend-backend
services:
- name: backend
azureFunction: backend/
pathToFunc: /npm/node_modules/node_modules/azure-functions-core-tools/bin/func.dll
- name: frontend
project: frontend/frontend.csproj

68
test/UnitTests/FuncFinderTests.cs

@ -1,68 +0,0 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Testing;
using Xunit;
namespace Microsoft.Tye.UnitTests
{
public class FuncFinderTests : LoggedTest
{
[Theory]
[InlineData("v2", "x64", "2.")]
[InlineData("v3", "x64", "3.")]
public async Task FuncInstallerReturnsRightPaths(string version, string arch, string expectedVersionPart)
{
var funcDownloader = new FuncDetector();
var path = await funcDownloader.PathToFunc(version, arch, downloadPath: null, logger: LoggerFactory.CreateLogger("AzureFunctionTest"), default, dryRun: true);
// Verifying this path is a bit tricky, version isn't easily associated.
// Using partial matches
//Assert.Contains(FuncDetector.GetAzureFunctionDirectory(), path);
Assert.Contains(expectedVersionPart, path);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)]
[InlineData("v2", "x86", "2.")]
[InlineData("v3", "x86", "3.")]
public async Task FuncInstallerReturnsRightPathsWindows(string version, string arch, string expectedVersionPart)
{
var funcDownloader = new FuncDetector();
var path = await funcDownloader.PathToFunc(version, arch, downloadPath: null, logger: LoggerFactory.CreateLogger("AzureFunctionTest"), default, dryRun: true);
// Verifying this path is a bit tricky, version isn't easily associated.
// Using partial matches
//Assert.Contains(FuncDetector.GetAzureFunctionDirectory(), path);
Assert.Contains(expectedVersionPart, path);
}
[Fact]
public async Task FuncInstallerWritesToDifferentDirectory()
{
using var tmp = TempDirectory.Create();
var funcDownloader = new FuncDetector();
var path = await funcDownloader.PathToFunc("v3", "x64", tmp.DirectoryPath, logger: LoggerFactory.CreateLogger("AzureFunctionTest"), default, dryRun: true);
Assert.Contains(tmp.DirectoryPath, path);
}
[Fact]
public async Task FuncInstallerLogsForV1SayingUnsupported()
{
var logger = LoggerFactory.CreateLogger("AzureFunctionTest");
var funcDownloader = new FuncDetector();
var path = await funcDownloader.PathToFunc("v1", "x64", downloadPath: null, logger: logger, default, dryRun: true);
Assert.Contains(TestSink.Writes, context => context.Message.Contains("Functions V1 are unsupported and untested in Tye."));
}
[Fact]
public async Task FuncInstallerThrowsForInvalidArch()
{
var funcDownloader = new FuncDetector();
await Assert.ThrowsAsync<NotSupportedException>(async () =>
await funcDownloader.PathToFunc("v3", "x64a", downloadPath: null, logger: LoggerFactory.CreateLogger("AzureFunctionTest"), default, dryRun: true));
}
}
}
Loading…
Cancel
Save