diff --git a/CHANGELOG.md b/CHANGELOG.md index 3689759880..0c9ce05208 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.0.28 - XX May 2018 +* Update .NET Core Dockerfile generation [#264](https://github.com/Microsoft/vscode-docker/issues/264). Per the .NET team, don't generate `docker-compose` files for .NET Core + ## 0.0.27 - 19 May 2018 * Fixes indentation problem with Python docker-compose.yml files (thanks @brettcannon) [#242](https://github.com/Microsoft/vscode-docker/pull/242) * Adds support for showing the Docker explorer in a new viewlet diff --git a/configureWorkspace/config-utils.ts b/configureWorkspace/config-utils.ts index e4ae257c41..229fe71adf 100644 --- a/configureWorkspace/config-utils.ts +++ b/configureWorkspace/config-utils.ts @@ -1,10 +1,10 @@ import vscode = require('vscode'); -export async function promptForPort(): Promise{ +export async function promptForPort(port: number): Promise{ var opt: vscode.InputBoxOptions = { - placeHolder: '3000', + placeHolder: `${port}`, prompt: 'What port does your app listen on?', - value: '3000' + value: `${port}` } return vscode.window.showInputBox(opt); @@ -20,10 +20,23 @@ export async function quickPickPlatform(): Promise{ const items: string[] = []; items.push('Go'); items.push('Java'); - items.push('.NET Core'); + items.push('.NET Core Console'); + items.push('ASP.NET Core'); items.push('Node.js'); items.push('Python'); items.push('Other'); return vscode.window.showQuickPick(items, opt); } + +export async function quickPickOS(): Promise { + var opt: vscode.QuickPickOptions = { + matchOnDescription: true, + matchOnDetail: true, + placeHolder: 'Select Operating System' + } + + const items: string[] = ['Windows', 'Linux']; + + return vscode.window.showQuickPick(items, opt); +} \ No newline at end of file diff --git a/configureWorkspace/configure.ts b/configureWorkspace/configure.ts index 374ab6076e..a3569c39d9 100644 --- a/configureWorkspace/configure.ts +++ b/configureWorkspace/configure.ts @@ -3,10 +3,12 @@ import * as path from 'path'; import * as fs from 'fs'; import * as pomParser from 'pom-parser'; import * as gradleParser from 'gradle-to-js/lib/parser'; -import { promptForPort, quickPickPlatform } from './config-utils'; +import * as glob from 'glob'; +import { promptForPort, quickPickPlatform, quickPickOS } from './config-utils'; import { reporter } from '../telemetry/telemetry'; +import { match } from 'minimatch'; -function genDockerFile(serviceName: string, platform: string, port: string, { cmd, author, version, artifactName }: PackageJson): string { +function genDockerFile(serviceName: string, platform: string, os: string, port: string, { cmd, author, version, artifactName }: PackageJson): string { switch (platform.toLowerCase()) { case 'node.js': @@ -39,17 +41,100 @@ LABEL Name=${serviceName} Version=${version} EXPOSE ${port} `; - case '.net core': + case '.net core console': - return ` -FROM microsoft/aspnetcore:1 -LABEL Name=${serviceName} Version=${version} -ARG source=. + if (os.toLowerCase() === 'windows') { + return ` + +FROM microsoft/dotnet:2.0-runtime-nanoserver-1709 AS base +WORKDIR /app + +FROM microsoft/dotnet:2.0-sdk-nanoserver-1709 AS build +WORKDIR /src +COPY ${serviceName}.csproj ${serviceName}/ +RUN dotnet restore ${serviceName}/${serviceName}.csproj +WORKDIR /src/${serviceName} +COPY . . +RUN dotnet build ${serviceName}.csproj -c Release -o /app + +FROM build AS publish +RUN dotnet publish ${serviceName}.csproj -c Release -o /app + +FROM base AS final +WORKDIR /app +COPY --from=publish /app . +ENTRYPOINT ["dotnet", "${serviceName}.dll"] +`; + } else { + return ` +FROM microsoft/dotnet:2.0-runtime AS base +WORKDIR /app + +FROM microsoft/dotnet:2.0-sdk AS build +WORKDIR /src +COPY ${serviceName}.csproj ${serviceName}/ +RUN dotnet restore ${serviceName}/${serviceName}.csproj +WORKDIR /src/${serviceName} +COPY . . +RUN dotnet build ${serviceName}.csproj -c Release -o /app + +FROM build AS publish +RUN dotnet publish ${serviceName}.csproj -c Release -o /app + +FROM base AS final +WORKDIR /app +COPY --from=publish /app . +ENTRYPOINT ["dotnet", "${serviceName}.dll"] +`; + } + + case 'asp.net core': + + if (os.toLowerCase() === 'windows') { + return ` +FROM microsoft/aspnetcore:2.0-nanoserver-1709 AS base +WORKDIR /app +EXPOSE ${port} + +FROM microsoft/aspnetcore-build:2.0-nanoserver-1709 AS build +WORKDIR /src +COPY ${serviceName}.csproj ${serviceName}/ +RUN dotnet restore ${serviceName}/${serviceName}.csproj +WORKDIR /src/${serviceName} +COPY . . +RUN dotnet build ${serviceName}.csproj -c Release -o /app + +FROM build AS publish +RUN dotnet publish ${serviceName}.csproj -c Release -o /app + +FROM base AS final +WORKDIR /app +COPY --from=publish /app . +ENTRYPOINT ["dotnet", "${serviceName}.dll"] +`; + } else { + return ` +FROM microsoft/aspnetcore:2.0 AS base WORKDIR /app EXPOSE ${port} -COPY $source . -ENTRYPOINT dotnet ${serviceName}.dll + +FROM microsoft/aspnetcore-build:2.0 AS build +WORKDIR /src +COPY ${serviceName}.csproj ${serviceName}/ +RUN dotnet restore ${serviceName}/${serviceName}.csproj +WORKDIR /src/${serviceName} +COPY . . +RUN dotnet build ${serviceName}.csproj -c Release -o /app + +FROM build AS publish +RUN dotnet publish ${serviceName}.csproj -c Release -o /app + +FROM base AS final +WORKDIR /app +COPY --from=publish /app . +ENTRYPOINT ["dotnet", "${serviceName}.dll"] `; + } case 'python': @@ -109,7 +194,7 @@ CMD /usr/games/fortune -a | cowsay } } -function genDockerCompose(serviceName: string, platform: string, port: string): string { +function genDockerCompose(serviceName: string, platform: string, os: string, port: string): string { switch (platform.toLowerCase()) { case 'node.js': return `version: '2.1' @@ -133,7 +218,19 @@ services: ports: - ${port}:${port}`; - case '.net core': + case '.net core console': + // we don't generate compose files for .net core + return `version: '2.1' + +services: + ${serviceName}: + image: ${serviceName} + build: . + ports: + - ${port}:${port}`; + + case 'asp.net core': + // we don't generate compose files for .net core return `version: '2.1' services: @@ -175,7 +272,7 @@ services: } } -function genDockerComposeDebug(serviceName: string, platform: string, port: string, { fullCommand: cmd }: PackageJson): string { +function genDockerComposeDebug(serviceName: string, platform: string, os: string, port: string, { fullCommand: cmd }: PackageJson): string { switch (platform.toLowerCase()) { case 'node.js': @@ -213,25 +310,27 @@ services: - ${port}:${port} `; - case '.net core': + case '.net core console': + // we don't generate compose files for .net core return `version: '2.1' services: ${serviceName}: - build: - args: - source: obj/Docker/empty/ - labels: - - "com.microsoft.visualstudio.targetoperatingsystem=linux" - environment: - - ASPNETCORE_ENVIRONMENT=Development - - DOTNET_USE_POLLING_FILE_WATCHER=1 - volumes: - - .:/app - - ~/.nuget/packages:/root/.nuget/packages:ro - - ~/clrdbg:/clrdbg:ro - entrypoint: tail -f /dev/null -`; + image: ${serviceName} + build: . + ports: + - ${port}:${port}`; + + case 'asp.net core': + // we don't generate compose files for .net core + return `version: '2.1' + +services: + ${serviceName}: + image: ${serviceName} + build: . + ports: + - ${port}:${port}`; case 'python': return `version: '2.1' @@ -277,7 +376,7 @@ services: } } -function genDockerIgnoreFile(service, platformType, port) { +function genDockerIgnoreFile(service: string, platformType: string, os: string, port: string) { // TODO: Add support for other platform types return `node_modules npm-debug.log @@ -390,6 +489,41 @@ async function readPomOrGradle(folder: vscode.WorkspaceFolder): Promise { + const opt: vscode.QuickPickOptions = { + matchOnDescription: true, + matchOnDetail: true, + placeHolder: 'Select Project' + } + + const projectFiles: string[] = await new Promise((resolve, reject) => { + + glob('**/*.csproj', { cwd: folder.uri.fsPath }, (err, matches: string[]) => { + if (err) { + reject(); + } else { + resolve(matches); + } + }); + + }); + + if (!projectFiles) { + return; + } + + if (projectFiles.length > 1) { + const res = await vscode.window.showQuickPick(projectFiles, opt); + if (res) { + return res.slice(0, -'.csproj'.length); + } else { + return; + } + } + + return projectFiles[0].slice(0, -'.csproj'.length); + +} const DOCKER_FILE_TYPES = { 'docker-compose.yml': genDockerCompose, 'docker-compose.debug.yml': genDockerComposeDebug, @@ -428,10 +562,28 @@ export async function configure(): Promise { const platformType = await quickPickPlatform(); if (!platformType) return; - const port = await promptForPort(); + var os; + if (platformType.toLowerCase().includes('.net')) { + os = await quickPickOS(); + if (!os) return; + } + + var port; + if (platformType.toLowerCase().includes('.net')) { + port = await promptForPort(80); + } else { + port = await promptForPort(3000); + } if (!port) return; - const serviceName = path.basename(folder.uri.fsPath).toLowerCase(); + var serviceName: string; + if (platformType.toLowerCase().includes('.net')) { + serviceName = await findCSProjFile(folder); + } else { + serviceName = path.basename(folder.uri.fsPath).toLowerCase(); + } + if (!serviceName) return; + let pkg: PackageJson = getDefaultPackageJson(); if (platformType.toLowerCase() === 'java') { pkg = await readPomOrGradle(folder); @@ -440,7 +592,10 @@ export async function configure(): Promise { } await Promise.all(Object.keys(DOCKER_FILE_TYPES).map((fileName) => { - return createWorkspaceFileIfNotExists(fileName, DOCKER_FILE_TYPES[fileName]); + // don't generate docker-compose files for .NET Core apps + if (platformType.toLowerCase().includes('.net') && !fileName.includes('docker-compose')) { + return createWorkspaceFileIfNotExists(fileName, DOCKER_FILE_TYPES[fileName]); + } })); /* __GDPR__ @@ -459,10 +614,10 @@ export async function configure(): Promise { if (fs.existsSync(workspacePath)) { const item: vscode.MessageItem = await vscode.window.showErrorMessage(`A ${fileName} already exists. Would you like to override it?`, ...YES_OR_NO_PROMPT); if (item.title.toLowerCase() === 'yes') { - fs.writeFileSync(workspacePath, writerFunction(serviceName, platformType, port, pkg), { encoding: 'utf8' }); + fs.writeFileSync(workspacePath, writerFunction(serviceName, platformType, os, port, pkg), { encoding: 'utf8' }); } } else { - fs.writeFileSync(workspacePath, writerFunction(serviceName, platformType, port, pkg), { encoding: 'utf8' }); + fs.writeFileSync(workspacePath, writerFunction(serviceName, platformType, os, port, pkg), { encoding: 'utf8' }); } } } diff --git a/package-lock.json b/package-lock.json index 763c1f36e6..9e6bd877ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,12 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/events": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", + "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", + "dev": true + }, "@types/form-data": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz", @@ -12,12 +18,29 @@ "@types/node": "8.0.53" } }, + "@types/glob": { + "version": "5.0.35", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.35.tgz", + "integrity": "sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg==", + "dev": true, + "requires": { + "@types/events": "1.2.0", + "@types/minimatch": "3.0.3", + "@types/node": "8.0.53" + } + }, "@types/keytar": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/keytar/-/keytar-4.0.1.tgz", "integrity": "sha1-4s9kBdwzhhQk5ZtnUWxm0s97whs=", "dev": true }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, "@types/node": { "version": "8.0.53", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.53.tgz", @@ -210,8 +233,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base64url": { "version": "2.0.0", @@ -267,7 +289,6 @@ "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true, "requires": { "balanced-match": "1.0.0", "concat-map": "0.0.1" @@ -368,8 +389,7 @@ "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 + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.5.2", @@ -961,8 +981,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fstream": { "version": "1.0.11", @@ -1001,7 +1020,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", - "dev": true, "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", @@ -1643,7 +1661,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "1.4.0", "wrappy": "1.0.2" @@ -2104,7 +2121,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", - "dev": true, "requires": { "brace-expansion": "1.1.8" } @@ -2340,8 +2356,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "pause-stream": { "version": "0.0.11", diff --git a/package.json b/package.json index 54fbfb0759..6a5d3540f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vscode-docker", - "version": "0.0.27", + "version": "0.0.28", "publisher": "PeterJausovec", "displayName": "Docker", "description": "Adds syntax highlighting, commands, hover tips, and linting for Dockerfile and docker-compose files.", @@ -620,7 +620,8 @@ "vscode": "^1.0.0", "typescript": "^2.1.5", "@types/node": "^8.0.34", - "@types/keytar": "^4.0.1" + "@types/keytar": "^4.0.1", + "@types/glob": "5.0.35" }, "dependencies": { "azure-arm-containerregistry": "^1.0.0-preview", @@ -634,6 +635,7 @@ "pom-parser": "^1.1.1", "request-promise": "^4.2.2", "vscode-extension-telemetry": "^0.0.6", - "vscode-languageclient": "^4.0.0" + "vscode-languageclient": "^4.0.0", + "glob": "7.1.2" } }