mirror of https://github.com/dotnet/tye.git
committed by
GitHub
87 changed files with 1276 additions and 449 deletions
@ -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 |
|||
|
|||
@ -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,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!; |
|||
} |
|||
} |
|||
} |
|||
@ -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,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>(); |
|||
}); |
|||
} |
|||
} |
|||
@ -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" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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!; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
{ |
|||
"Logging": { |
|||
"LogLevel": { |
|||
"Default": "Information", |
|||
"Microsoft": "Warning", |
|||
"Microsoft.Hosting.Lifetime": "Information" |
|||
} |
|||
} |
|||
} |
|||
@ -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> |
|||
@ -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 |
|||
@ -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(/|$)(.*) |
|||
@ -0,0 +1,6 @@ |
|||
*.js.map |
|||
*.ts |
|||
.git* |
|||
.vscode |
|||
local.settings.json |
|||
test |
|||
@ -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 |
|||
@ -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" |
|||
} |
|||
@ -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; |
|||
@ -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)" |
|||
} |
|||
} |
|||
@ -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" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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" |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
{ |
|||
"compilerOptions": { |
|||
"module": "commonjs", |
|||
"target": "es6", |
|||
"outDir": "dist", |
|||
"rootDir": ".", |
|||
"sourceMap": true, |
|||
"strict": false |
|||
} |
|||
} |
|||
@ -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. |
|||
@ -0,0 +1,3 @@ |
|||
services: |
|||
- name: HttpExample |
|||
azureFunction: HttpExample/ |
|||
@ -0,0 +1,10 @@ |
|||
{ |
|||
"Logging": { |
|||
"LogLevel": { |
|||
"Default": "Information", |
|||
"Microsoft": "Warning", |
|||
"Microsoft.Hosting.Lifetime": "Information" |
|||
} |
|||
}, |
|||
"AllowedHosts": "*" |
|||
} |
|||
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
@ -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,0 +1,11 @@ |
|||
{ |
|||
"version": "2.0", |
|||
"logging": { |
|||
"applicationInsights": { |
|||
"samplingExcludedTypes": "Request", |
|||
"samplingSettings": { |
|||
"isEnabled": true |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,7 +0,0 @@ |
|||
{ |
|||
"IsEncrypted": false, |
|||
"Values": { |
|||
"AzureWebJobsStorage": "UseDevelopmentStorage=true", |
|||
"FUNCTIONS_WORKER_RUNTIME": "dotnet" |
|||
} |
|||
} |
|||
@ -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."); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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…
Reference in new issue