Compare commits

..

39 Commits
1.7.0 ... 1.6.0

Author SHA1 Message Date
Karl Burtram
eb35dae1d1 Turn off failing Insights tests 2019-04-16 22:59:03 -07:00
Karl Burtram
cc0a144169 Remove gap from bottom of Server view (#5072) 2019-04-16 19:54:30 -07:00
Anthony Dresser
b973f9e0ec changes strings for data explorer (#4946) 2019-04-16 18:49:59 -07:00
Alan Ren
d62068025c Merge fix the selectbox issue for chart 2019-04-16 13:40:24 -07:00
Aditya Bist
b2952d2ddf fix job action context (#5053) 2019-04-16 13:36:30 -07:00
Gene Lee
a21244816d Add support for new endpoint key string 'gateway' (#4954) 2019-04-16 10:45:00 -07:00
Chris LaFreniere
a9aeb57dc4 Fix to ensure that we rewrite spark ui links correctly (#4962) 2019-04-16 10:34:01 -07:00
Gene Lee
00537ed199 Fixed bug: CheckboxTreeNode label overflows, and node icon disappears (#5022) 2019-04-16 10:31:40 -07:00
Alex Ross
c2df3e0e0a Merge 51b0b28134d51361cf996d2f0a1c698247aeabd8 2019-04-15 10:15:55 -07:00
Charles Gagnon
e3afb1cffc Fix wrong release notes being loaded (#5008) 2019-04-11 20:56:19 -07:00
Kevin Cunnane
b475311f85 Fix #4500 Untitled notebook reopen doesn't show dirty (#5005)
* Fix 2 notebook issues
- Do not create notebook model twice on start
- Do not cause disposed warnings due to markdown cell deserialization

* Fix notebook dirty on open issue
Before model is resolved we weren't getting dirty events.
Solution is to use backing text model until it's ready.
Must hook to the dirty event & notify to get the dot to appear

# Conflicts:
#	src/sql/workbench/parts/notebook/cellViews/code.component.ts
2019-04-11 20:56:03 -07:00
Maddy
45005d61e0 add wrap to the <pre> tag (#5002)
* add wrap to the <pre> tag

* removed styles for browser support
2019-04-11 20:46:41 -07:00
Anthony Dresser
adfddeae27 restore line height to account list renderer (#4999) 2019-04-11 20:46:27 -07:00
Anthony Dresser
a7429267bb revert data explorer id to connections (#5003) 2019-04-11 20:46:08 -07:00
kisantia
ff415d6a03 bump SQL Tools to 1.5.0-alpha.85 to get invalid dacpac version fix (#5001) 2019-04-11 15:25:55 -07:00
udeeshagautam
b4dc35a4de Fix for 4104 : Multiple consecutive spaces in query results cells are condensed into one (#4983)
* preserving spaces in query results - all beginning, trailing and middle spaces will be shown as is

* removing the change through formatting and replacing with css change formatting was leaving special char while removing nbsp
2019-04-11 15:25:41 -07:00
Aditya Bist
29c7ccad39 Added some usage details (#4711)
* added some details

* remove unused import

* added new metrics, removed churn

* merged master and code review comments

* code review comments

* normalized days to calendar days/weeks/months

* cleaned up code

* changed comment to start required check for PR

* fix failing test

* fix test

* removed null assignment

* fix null test script
2019-04-11 15:25:24 -07:00
Yurong He
1da3635d03 Fix ##3479 ctrl+a select active cell output or preview markdown (#4981)
* Enable ctrl+a to select the output or markdown content when the cell is active

* Moved toggleUserSelect into ngOnChanges

* Resolve PR comments
2019-04-11 15:25:02 -07:00
Chris LaFreniere
1f50015ed2 Add New Notebook from Server Dashboard (#4971) 2019-04-11 15:24:47 -07:00
Aditya Bist
01892422cb Azure extension changes (#4987)
* removed search box

* removed commented code

# Conflicts:
#	src/sql/parts/objectExplorer/viewlet/serverTreeView.ts
2019-04-11 15:24:31 -07:00
Cory Rivera
afce60b06f Add additional error handling to Python installation for Notebooks (#4891)
* Also enabled integration tests for python installation.
2019-04-11 15:01:02 -07:00
Chris LaFreniere
a2b87f6158 Fix for relative markdown image paths (#4889)
* Fix for relative markdown image paths

* PR comments
2019-04-11 15:00:45 -07:00
Chris LaFreniere
76a2f92daf Notebooks: Potential Fix for "Notebook Provider does not Exist" Error (#4848)
* Fallback to SQL

* Fix providers not found issue

* await whenInstalledExtensionsRegistered

* PR comments
2019-04-11 15:00:21 -07:00
Gene Lee
5b09d57196 Fixed Broken Notebook Preview (#4895) 2019-04-11 14:59:09 -07:00
Karl Burtram
95bf18f859 Fix merge build break 2019-04-10 16:16:43 -07:00
Kevin Cunnane
1fc648ff37 Mitigate (but not fully fix) Run Cell from disconnected notebook (#4960)
This is a partial fix that lays groundwork for full "Prompt to connect" if a kernel needs a connection.
I am waiting on Yurong's refactoring of connection handling before doing any of the prompt work.

- Adds kernel metadata about whether a connection is required.
- For Jupyter, only Spark kernels are listed as requiring a connection
- If this is true and there's no active connection, will show notification and not call execute

In the future, this path will still be used if user is prompted to connect and cancels out.
The future change will be to inject a "connect" handler from notebook.component to the cell callback and use to set connection context
2019-04-10 13:50:23 -07:00
Kevin Cunnane
37ba956bad Fix #4893 New Notebook Can Open Existing Noteboon (#4959)
Add back check for textDocuments with same name, should've been there anyhow

On rehydration files show as text docs before clicking as only get
changed by customInputConverter code path.
We should look at this long term - ideally we'd update notebookDocuments
with correct values on initial start. #4958 opened to track this.
2019-04-10 13:47:49 -07:00
Kevin Cunnane
697f887539 Fix #4930 Text cells are referred to as text and markdown in commands (#4956) 2019-04-10 13:44:20 -07:00
Anthony Dresser
7b42141958 Merge 2de47c2a50 2019-04-10 13:44:11 -07:00
Chris LaFreniere
158b00f9b4 always serialize execution count (#4864) 2019-04-10 13:39:54 -07:00
Matt Bierner
43ac8dfd20 Adopt TS 3.4.3
Fixes #72005
2019-04-10 13:30:11 -07:00
Sandeep Somavarapu
34d8d52e7a Fix #71947 2019-04-09 13:09:10 -07:00
Sandeep Somavarapu
c738b26c04 Fix #71585 2019-04-09 13:09:03 -07:00
Johannes Rieken
6090e7173f properly check picked formatter, #71988 2019-04-09 13:06:45 -07:00
Johannes Rieken
7ebf746584 use editor for format on save and honor silent mode 2019-04-09 13:06:36 -07:00
Matt Bierner
e9d04d75ac Fixes #71688 2019-04-09 13:06:20 -07:00
Joao Moreno
605160a1ba Cherry pick 3773487012c98ef7974a0182771ea19178f2a525 2019-04-09 13:04:37 -07:00
Johannes Rieken
82b8750b63 show notification when formatter is disabled/uninstalled, message otherwise 2019-04-09 12:59:00 -07:00
Rob Lourens
61f7f19d12 Fix #71465 - "find in files shortcut broken" 2019-04-09 12:58:48 -07:00
2108 changed files with 84071 additions and 122579 deletions

6
.vscode/launch.json vendored
View File

@@ -70,12 +70,10 @@
"timeout": 20000 "timeout": 20000
}, },
"osx": { "osx": {
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh", "runtimeExecutable": "${workspaceFolder}/scripts/sql.sh"
"timeout": 20000
}, },
"linux": { "linux": {
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh", "runtimeExecutable": "${workspaceFolder}/scripts/sql.sh"
"timeout": 20000
}, },
"env": { "env": {
"VSCODE_EXTHOST_WILL_SEND_SOCKET": null "VSCODE_EXTHOST_WILL_SEND_SOCKET": null

14
.vscode/tasks.json vendored
View File

@@ -28,20 +28,6 @@
} }
} }
}, },
{
"type": "npm",
"script": "strict-initialization-watch",
"label": "TS - Strict Initialization",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"problemMatcher": {
"base": "$tsc-watch",
"owner": "typescript-strict-initialization",
"applyTo": "allDocuments"
}
},
{ {
"type": "gulp", "type": "gulp",
"task": "tslint", "task": "tslint",

View File

@@ -1,3 +1,3 @@
disturl "https://atom.io/download/electron" disturl "https://atom.io/download/electron"
target "3.1.8" target "3.1.6"
runtime "electron" runtime "electron"

View File

@@ -1,18 +1,5 @@
# Change Log # Change Log
## Version 1.6.0
* Release date: April 18, 2019
* Release status: General Availability
## What's new in this version
* Align with latest VS Code editor platform (currently 1.33.1)
* Resolved [bugs and issues](https://github.com/Microsoft/azuredatastudio/milestone/26?closed=1).
## Contributions and "thank you"
We would like to thank all our users who raised issues, and in particular the following users who helped contribute fixes:
* yamatoya for `fix the format (#4899)`
## Version 1.5.1 ## Version 1.5.1
* Release date: March 18, 2019 * Release date: March 18, 2019
* Release status: General Availability * Release status: General Availability

View File

@@ -9,13 +9,13 @@ Azure Data Studio is a data management tool that enables you to work with SQL Se
Platform | Link Platform | Link
-- | -- -- | --
Windows User Installer | https://go.microsoft.com/fwlink/?linkid=2087316 Windows User Installer | https://go.microsoft.com/fwlink/?linkid=2083322
Windows System Installer | https://go.microsoft.com/fwlink/?linkid=2087317 Windows System Installer | https://go.microsoft.com/fwlink/?linkid=2083323
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=2087318 Windows ZIP | https://go.microsoft.com/fwlink/?linkid=2083324
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=2087170 macOS ZIP | https://go.microsoft.com/fwlink/?linkid=2083325
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=2087414 Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=2083424
Linux RPM | https://go.microsoft.com/fwlink/?linkid=2087171 Linux RPM | https://go.microsoft.com/fwlink/?linkid=2083326
Linux DEB | https://go.microsoft.com/fwlink/?linkid=2087415 Linux DEB | https://go.microsoft.com/fwlink/?linkid=2083327
Go to our [download page](https://aka.ms/azuredatastudio) for more specific instructions. Go to our [download page](https://aka.ms/azuredatastudio) for more specific instructions.
@@ -68,7 +68,6 @@ The [Microsoft Enterprise and Developer Privacy Statement](https://privacy.micro
## Contributions and "Thank You" ## Contributions and "Thank You"
We would like to thank all our users who raised issues, and in particular the following users who helped contribute fixes: We would like to thank all our users who raised issues, and in particular the following users who helped contribute fixes:
* yamatoya for `fix the format (#4899)`
* GeoffYoung for `Fix sqlDropColumn description #4422` * GeoffYoung for `Fix sqlDropColumn description #4422`
* AlexFsmn for `Added context menu for DBs in explorer view to backup & restore db. #2277` * AlexFsmn for `Added context menu for DBs in explorer view to backup & restore db. #2277`
* sadedil for `Missing feature request: Save as XML #3729` * sadedil for `Missing feature request: Save as XML #3729`

View File

@@ -27,12 +27,18 @@ steps:
displayName: 'Install' displayName: 'Install'
- script: | - script: |
yarn gulp electron-x64 node_modules/.bin/gulp electron
displayName: Download Electron node_modules/.bin/gulp compile --max_old_space_size=4096
displayName: 'Scripts'
- script: | - script: |
yarn gulp hygiene DISPLAY=:10 ./scripts/test.sh --reporter mocha-junit-reporter
displayName: Run Hygiene Checks displayName: 'Tests'
- task: PublishTestResults@2
inputs:
testResultsFiles: '**/test-results.xml'
condition: succeededOrFailed()
- script: | - script: |
yarn tslint yarn tslint
@@ -41,29 +47,3 @@ steps:
- script: | - script: |
yarn strict-null-check yarn strict-null-check
displayName: 'Run Strict Null Check' displayName: 'Run Strict Null Check'
- script: |
yarn compile
displayName: 'Compile'
- script: |
DISPLAY=:10 ./scripts/test.sh --reporter mocha-junit-reporter
displayName: 'Tests'
condition: eq(variables['Agent.OS'], 'Linux')
- script: |
DISPLAY=:10 ./scripts/test.sh --reporter mocha-junit-reporter --coverage
displayName: 'Tests'
condition: ne(variables['Agent.OS'], 'Linux')
- task: PublishTestResults@2
inputs:
testResultsFiles: '**/test-results.xml'
condition: succeededOrFailed()
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: 'cobertura'
summaryFileLocation: $(System.DefaultWorkingDirectory)/.build/coverage/cobertura-coverage.xml
reportDirectory: $(System.DefaultWorkingDirectory)/.build/coverage/lcov-reports
condition: ne(variables['Agent.OS'], 'Linux')

View File

@@ -9,12 +9,21 @@ steps:
displayName: 'Yarn Install' displayName: 'Yarn Install'
- script: | - script: |
yarn gulp electron-x64 .\node_modules\.bin\gulp electron
displayName: 'Electron' displayName: 'Electron'
- script: | - script: |
yarn gulp hygiene npm run compile
displayName: Run Hygiene Checks displayName: 'Compile'
- script: |
.\scripts\test.bat --reporter mocha-junit-reporter
displayName: 'Test'
- task: PublishTestResults@2
inputs:
testResultsFiles: 'test-results.xml'
condition: succeededOrFailed()
- script: | - script: |
yarn tslint yarn tslint
@@ -23,22 +32,3 @@ steps:
- script: | - script: |
yarn strict-null-check yarn strict-null-check
displayName: 'Run Strict Null Check' displayName: 'Run Strict Null Check'
- script: |
yarn compile
displayName: 'Compile'
- script: |
.\scripts\test.bat --reporter mocha-junit-reporter --coverage
displayName: 'Test'
- task: PublishTestResults@2
inputs:
testResultsFiles: 'test-results.xml'
condition: succeededOrFailed()
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: 'cobertura'
summaryFileLocation: $(System.DefaultWorkingDirectory)\.build\coverage\cobertura-coverage.xml
reportDirectory: $(System.DefaultWorkingDirectory)\.build\coverage\lcov-report

View File

@@ -65,7 +65,8 @@ interface Asset {
platform: string; platform: string;
type: string; type: string;
url: string; url: string;
mooncakeUrl?: string; // {{SQL CARBON EDIT}}
mooncakeUrl: string | undefined;
hash: string; hash: string;
sha256hash: string; sha256hash: string;
size: number; size: number;
@@ -188,18 +189,56 @@ async function publish(commit: string, quality: string, platform: string, type:
const blobService = azure.createBlobService(storageAccount, process.env['AZURE_STORAGE_ACCESS_KEY_2']!) const blobService = azure.createBlobService(storageAccount, process.env['AZURE_STORAGE_ACCESS_KEY_2']!)
.withFilter(new azure.ExponentialRetryPolicyFilter(20)); .withFilter(new azure.ExponentialRetryPolicyFilter(20));
// {{SQL CARBON EDIT}}
await assertContainer(blobService, quality); await assertContainer(blobService, quality);
const blobExists = await doesAssetExist(blobService, quality, blobName); const blobExists = await doesAssetExist(blobService, quality, blobName);
if (blobExists) { const promises = [];
if (!blobExists) {
promises.push(uploadBlob(blobService, quality, blobName, file));
}
// {{SQL CARBON EDIT}}
if (process.env['MOONCAKE_STORAGE_ACCESS_KEY']) {
const mooncakeBlobService = azure.createBlobService(storageAccount, process.env['MOONCAKE_STORAGE_ACCESS_KEY']!, `${storageAccount}.blob.core.chinacloudapi.cn`)
.withFilter(new azure.ExponentialRetryPolicyFilter(20));
// mooncake is fussy and far away, this is needed!
mooncakeBlobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000;
await Promise.all([
assertContainer(blobService, quality),
assertContainer(mooncakeBlobService, quality)
]);
const [blobExists, moooncakeBlobExists] = await Promise.all([
doesAssetExist(blobService, quality, blobName),
doesAssetExist(mooncakeBlobService, quality, blobName)
]);
const promises: Array<Promise<void>> = [];
if (!blobExists) {
promises.push(uploadBlob(blobService, quality, blobName, file));
}
if (!moooncakeBlobExists) {
promises.push(uploadBlob(mooncakeBlobService, quality, blobName, file));
}
} else {
console.log('Skipping Mooncake publishing.');
}
if (promises.length === 0) {
console.log(`Blob ${quality}, ${blobName} already exists, not publishing again.`); console.log(`Blob ${quality}, ${blobName} already exists, not publishing again.`);
return; return;
} }
console.log('Uploading blobs to Azure storage...'); console.log('Uploading blobs to Azure storage...');
await uploadBlob(blobService, quality, blobName, file); await Promise.all(promises);
console.log('Blobs successfully uploaded.'); console.log('Blobs successfully uploaded.');
@@ -211,6 +250,8 @@ async function publish(commit: string, quality: string, platform: string, type:
platform: platform, platform: platform,
type: type, type: type,
url: `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`, url: `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`,
// {{SQL CARBON EDIT}}
mooncakeUrl: process.env['MOONCAKE_CDN_URL'] ? `${process.env['MOONCAKE_CDN_URL']}/${quality}/${blobName}` : undefined,
hash: sha1hash, hash: sha1hash,
sha256hash, sha256hash,
size size

View File

@@ -1,176 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as url from 'url';
import * as azure from 'azure-storage';
import * as mime from 'mime';
import { DocumentClient, RetrievedDocument } from 'documentdb';
function log(...args: any[]) {
console.log(...[`[${new Date().toISOString()}]`, ...args]);
}
function error(...args: any[]) {
console.error(...[`[${new Date().toISOString()}]`, ...args]);
}
if (process.argv.length < 3) {
error('Usage: node sync-mooncake.js <quality>');
process.exit(-1);
}
interface Build extends RetrievedDocument {
assets: Asset[];
}
interface Asset {
platform: string;
type: string;
url: string;
mooncakeUrl: string;
hash: string;
sha256hash: string;
size: number;
supportsFastUpdate?: boolean;
}
function updateBuild(commit: string, quality: string, platform: string, type: string, asset: Asset): Promise<void> {
const client = new DocumentClient(process.env['AZURE_DOCUMENTDB_ENDPOINT']!, { masterKey: process.env['AZURE_DOCUMENTDB_MASTERKEY'] });
const collection = 'dbs/builds/colls/' + quality;
const updateQuery = {
query: 'SELECT TOP 1 * FROM c WHERE c.id = @id',
parameters: [{ name: '@id', value: commit }]
};
let updateTries = 0;
function _update(): Promise<void> {
updateTries++;
return new Promise<void>((c, e) => {
client.queryDocuments(collection, updateQuery).toArray((err, results) => {
if (err) { return e(err); }
if (results.length !== 1) { return e(new Error('No documents')); }
const release = results[0];
release.assets = [
...release.assets.filter((a: any) => !(a.platform === platform && a.type === type)),
asset
];
client.replaceDocument(release._self, release, err => {
if (err && err.code === 409 && updateTries < 5) { return c(_update()); }
if (err) { return e(err); }
log('Build successfully updated.');
c();
});
});
});
}
return _update();
}
async function sync(commit: string, quality: string): Promise<void> {
log(`Synchronizing Mooncake assets for ${quality}, ${commit}...`);
const cosmosdb = new DocumentClient(process.env['AZURE_DOCUMENTDB_ENDPOINT']!, { masterKey: process.env['AZURE_DOCUMENTDB_MASTERKEY'] });
const collection = `dbs/builds/colls/${quality}`;
const query = {
query: 'SELECT TOP 1 * FROM c WHERE c.id = @id',
parameters: [{ name: '@id', value: commit }]
};
const build = await new Promise<Build>((c, e) => {
cosmosdb.queryDocuments(collection, query).toArray((err, results) => {
if (err) { return e(err); }
if (results.length !== 1) { return e(new Error('No documents')); }
c(results[0] as Build);
});
});
log(`Found build for ${commit}, with ${build.assets.length} assets`);
const storageAccount = process.env['AZURE_STORAGE_ACCOUNT_2']!;
const blobService = azure.createBlobService(storageAccount, process.env['AZURE_STORAGE_ACCESS_KEY_2']!)
.withFilter(new azure.ExponentialRetryPolicyFilter(20));
const mooncakeBlobService = azure.createBlobService(storageAccount, process.env['MOONCAKE_STORAGE_ACCESS_KEY']!, `${storageAccount}.blob.core.chinacloudapi.cn`)
.withFilter(new azure.ExponentialRetryPolicyFilter(20));
// mooncake is fussy and far away, this is needed!
blobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000;
mooncakeBlobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000;
for (const asset of build.assets) {
try {
const blobPath = url.parse(asset.url).path;
if (!blobPath) {
throw new Error(`Failed to parse URL: ${asset.url}`);
}
const blobName = blobPath.replace(/^\/\w+\//, '');
log(`Found ${blobName}`);
if (asset.mooncakeUrl) {
log(` Already in Mooncake ✔️`);
continue;
}
const readStream = blobService.createReadStream(quality, blobName, undefined!);
const blobOptions: azure.BlobService.CreateBlockBlobRequestOptions = {
contentSettings: {
contentType: mime.lookup(blobPath),
cacheControl: 'max-age=31536000, public'
}
};
const writeStream = mooncakeBlobService.createWriteStreamToBlockBlob(quality, blobName, blobOptions, undefined);
log(` Uploading to Mooncake...`);
await new Promise((c, e) => readStream.pipe(writeStream).on('finish', c).on('error', e));
log(` Updating build in DB...`);
asset.mooncakeUrl = `${process.env['MOONCAKE_CDN_URL']}${blobPath}`;
await updateBuild(commit, quality, asset.platform, asset.type, asset);
log(` Done ✔️`);
} catch (err) {
error(err);
}
}
log(`All done ✔️`);
}
function main(): void {
if (process.env['VSCODE_BUILD_SKIP_PUBLISH']) {
error('Skipping publish due to VSCODE_BUILD_SKIP_PUBLISH');
return;
}
const commit = process.env['BUILD_SOURCEVERSION'];
if (!commit) {
error('Skipping publish due to missing BUILD_SOURCEVERSION');
return;
}
const quality = process.argv[2];
sync(commit, quality).catch(err => {
error(err);
process.exit(1);
});
}
main();

View File

@@ -1,4 +0,0 @@
#!/usr/bin/env bash
set -e
yarn gulp vscode-darwin-min
yarn gulp upload-vscode-sourcemaps

View File

@@ -18,15 +18,9 @@ steps:
password $(VSCODE_MIXIN_PASSWORD) password $(VSCODE_MIXIN_PASSWORD)
EOF EOF
git config user.email "vscode@microsoft.com"
git config user.name "VSCode"
git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git"
git fetch distro
git merge $(node -p "require('./package.json').distro")
yarn yarn
yarn gulp mixin VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" yarn gulp -- mixin
yarn gulp hygiene yarn gulp -- hygiene
yarn monaco-compile-check yarn monaco-compile-check
node build/azure-pipelines/common/installDistro.js node build/azure-pipelines/common/installDistro.js
node build/lib/builtInExtensions.js node build/lib/builtInExtensions.js
@@ -36,7 +30,10 @@ steps:
set -e set -e
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \ AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \
./build/azure-pipelines/darwin/build.sh yarn gulp -- vscode-darwin-min
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \
yarn gulp -- upload-vscode-sourcemaps
displayName: Build displayName: Build
- script: | - script: |
@@ -46,11 +43,6 @@ steps:
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-darwin/$APP_NAME" # yarn smoketest -- --build "$(agent.builddirectory)/VSCode-darwin/$APP_NAME"
displayName: Run unit tests displayName: Run unit tests
- script: |
set -e
./scripts/test-integration.sh --build --tfs "Integration Tests"
displayName: Run integration tests
- script: | - script: |
set -e set -e
pushd ../VSCode-darwin && zip -r -X -y ../VSCode-darwin.zip * && popd pushd ../VSCode-darwin && zip -r -X -y ../VSCode-darwin.zip * && popd
@@ -77,12 +69,31 @@ steps:
- script: | - script: |
set -e set -e
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
# remove pkg from archive
zip -d ../VSCode-darwin.zip "*.pkg"
# publish the build
PACKAGEJSON=`ls ../VSCode-darwin/*.app/Contents/Resources/app/package.json`
VERSION=`node -p "require(\"$PACKAGEJSON\").version"`
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \ MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
./build/azure-pipelines/darwin/publish.sh node build/azure-pipelines/common/publish.js \
"$(VSCODE_QUALITY)" \
darwin \
archive \
"VSCode-darwin-$(VSCODE_QUALITY).zip" \
$VERSION \
true \
../VSCode-darwin.zip
# publish hockeyapp symbols
node build/azure-pipelines/common/symbols.js "$(VSCODE_MIXIN_PASSWORD)" "$(VSCODE_HOCKEYAPP_TOKEN)" "$(VSCODE_ARCH)" "$(VSCODE_HOCKEYAPP_ID_MACOS)"
# upload configuration
AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \
yarn gulp -- upload-vscode-configuration
displayName: Publish displayName: Publish
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0

View File

@@ -1,22 +0,0 @@
#!/usr/bin/env bash
# remove pkg from archive
zip -d ../VSCode-darwin.zip "*.pkg"
# publish the build
PACKAGEJSON=`ls ../VSCode-darwin/*.app/Contents/Resources/app/package.json`
VERSION=`node -p "require(\"$PACKAGEJSON\").version"`
node build/azure-pipelines/common/publish.js \
"$VSCODE_QUALITY" \
darwin \
archive \
"VSCode-darwin-$VSCODE_QUALITY.zip" \
$VERSION \
true \
../VSCode-darwin.zip
# publish hockeyapp symbols
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_MACOS"
# upload configuration
yarn gulp upload-vscode-configuration

View File

@@ -1,30 +0,0 @@
trigger:
branches:
include: ['master', 'release/*']
pr:
branches:
include: ['master', 'release/*']
steps:
- task: NodeTool@0
inputs:
versionSpec: "10.15.1"
- script: |
set -e
cat << EOF > ~/.netrc
machine github.com
login vscode
password $(VSCODE_MIXIN_PASSWORD)
EOF
git config user.email "vscode@microsoft.com"
git config user.name "VSCode"
git remote add distro "https://github.com/$VSCODE_MIXIN_REPO.git"
git fetch distro
git push distro origin/master:refs/heads/master
git merge $(node -p "require('./package.json').distro")
displayName: Sync & Merge Distro

View File

@@ -1,3 +0,0 @@
#!/usr/bin/env bash
set -e
yarn gulp "vscode-linux-$VSCODE_ARCH-min"

View File

@@ -22,45 +22,90 @@ steps:
password $(VSCODE_MIXIN_PASSWORD) password $(VSCODE_MIXIN_PASSWORD)
EOF EOF
git config user.email "vscode@microsoft.com"
git config user.name "VSCode"
git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git"
git fetch distro
git merge $(node -p "require('./package.json').distro")
CHILD_CONCURRENCY=1 yarn CHILD_CONCURRENCY=1 yarn
yarn gulp mixin VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- mixin
yarn gulp hygiene npm run gulp -- hygiene
yarn monaco-compile-check npm run monaco-compile-check
node build/azure-pipelines/common/installDistro.js node build/azure-pipelines/common/installDistro.js
node build/lib/builtInExtensions.js node build/lib/builtInExtensions.js
displayName: Prepare build
- script: | - script: |
set -e set -e
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- vscode-linux-$(VSCODE_ARCH)-min
./build/azure-pipelines/linux/build.sh name: build
displayName: Build
- script: | - script: |
set -e set -e
yarn gulp "electron-$(VSCODE_ARCH)" npm run gulp -- "electron-$(VSCODE_ARCH)"
# xvfb seems to be crashing often, let's make sure it's always up # xvfb seems to be crashing often, let's make sure it's always up
service xvfb start service xvfb start
DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests" DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests"
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)" # yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)"
displayName: Run unit tests name: test
- script: | - script: |
set -e set -e
REPO="$(pwd)"
ROOT="$REPO/.."
ARCH="$(VSCODE_ARCH)"
# Publish tarball
PLATFORM_LINUX="linux-$(VSCODE_ARCH)"
[[ "$ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64"
[[ "$ARCH" == "ia32" ]] && RPM_ARCH="i386" || RPM_ARCH="x86_64"
BUILDNAME="VSCode-$PLATFORM_LINUX"
BUILD="$ROOT/$BUILDNAME"
BUILD_VERSION="$(date +%s)"
[ -z "$VSCODE_QUALITY" ] && TARBALL_FILENAME="code-$BUILD_VERSION.tar.gz" || TARBALL_FILENAME="code-$VSCODE_QUALITY-$BUILD_VERSION.tar.gz"
TARBALL_PATH="$ROOT/$TARBALL_FILENAME"
PACKAGEJSON="$BUILD/resources/app/package.json"
VERSION=$(node -p "require(\"$PACKAGEJSON\").version")
rm -rf $ROOT/code-*.tar.*
(cd $ROOT && tar -czf $TARBALL_PATH $BUILDNAME)
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \ node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_LINUX" archive-unsigned "$TARBALL_FILENAME" "$VERSION" true "$TARBALL_PATH"
./build/azure-pipelines/linux/publish.sh
displayName: Publish # Publish hockeyapp symbols
node build/azure-pipelines/common/symbols.js "$(VSCODE_MIXIN_PASSWORD)" "$(VSCODE_HOCKEYAPP_TOKEN)" "$(VSCODE_ARCH)" "$(VSCODE_HOCKEYAPP_ID_LINUX64)"
# Publish DEB
npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-deb"
PLATFORM_DEB="linux-deb-$ARCH"
[[ "$ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64"
DEB_FILENAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/)"
DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME"
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_DEB" package "$DEB_FILENAME" "$VERSION" true "$DEB_PATH"
# Publish RPM
npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-rpm"
PLATFORM_RPM="linux-rpm-$ARCH"
[[ "$ARCH" == "ia32" ]] && RPM_ARCH="i386" || RPM_ARCH="x86_64"
RPM_FILENAME="$(ls $REPO/.build/linux/rpm/$RPM_ARCH/ | grep .rpm)"
RPM_PATH="$REPO/.build/linux/rpm/$RPM_ARCH/$RPM_FILENAME"
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_RPM" package "$RPM_FILENAME" "$VERSION" true "$RPM_PATH"
# Publish Snap
npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-prepare-snap"
# Pack snap tarball artifact, in order to preserve file perms
mkdir -p $REPO/.build/linux/snap-tarball
SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-$(VSCODE_ARCH).tar.gz"
rm -rf $SNAP_TARBALL_PATH
(cd .build/linux && tar -czf $SNAP_TARBALL_PATH snap)
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
displayName: 'Component Detection' displayName: 'Component Detection'

View File

@@ -1,51 +0,0 @@
#!/usr/bin/env bash
set -e
REPO="$(pwd)"
ROOT="$REPO/.."
# Publish tarball
PLATFORM_LINUX="linux-$VSCODE_ARCH"
[[ "$VSCODE_ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64"
[[ "$VSCODE_ARCH" == "ia32" ]] && RPM_ARCH="i386" || RPM_ARCH="x86_64"
BUILDNAME="VSCode-$PLATFORM_LINUX"
BUILD="$ROOT/$BUILDNAME"
BUILD_VERSION="$(date +%s)"
[ -z "$VSCODE_QUALITY" ] && TARBALL_FILENAME="code-$BUILD_VERSION.tar.gz" || TARBALL_FILENAME="code-$VSCODE_QUALITY-$BUILD_VERSION.tar.gz"
TARBALL_PATH="$ROOT/$TARBALL_FILENAME"
PACKAGEJSON="$BUILD/resources/app/package.json"
VERSION=$(node -p "require(\"$PACKAGEJSON\").version")
rm -rf $ROOT/code-*.tar.*
(cd $ROOT && tar -czf $TARBALL_PATH $BUILDNAME)
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_LINUX" archive-unsigned "$TARBALL_FILENAME" "$VERSION" true "$TARBALL_PATH"
# Publish hockeyapp symbols
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_LINUX64"
# Publish DEB
yarn gulp "vscode-linux-$VSCODE_ARCH-build-deb"
PLATFORM_DEB="linux-deb-$VSCODE_ARCH"
[[ "$VSCODE_ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64"
DEB_FILENAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/)"
DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME"
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_DEB" package "$DEB_FILENAME" "$VERSION" true "$DEB_PATH"
# Publish RPM
yarn gulp "vscode-linux-$VSCODE_ARCH-build-rpm"
PLATFORM_RPM="linux-rpm-$VSCODE_ARCH"
[[ "$VSCODE_ARCH" == "ia32" ]] && RPM_ARCH="i386" || RPM_ARCH="x86_64"
RPM_FILENAME="$(ls $REPO/.build/linux/rpm/$RPM_ARCH/ | grep .rpm)"
RPM_PATH="$REPO/.build/linux/rpm/$RPM_ARCH/$RPM_FILENAME"
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_RPM" package "$RPM_FILENAME" "$VERSION" true "$RPM_PATH"
# Publish Snap
yarn gulp "vscode-linux-$VSCODE_ARCH-prepare-snap"
# Pack snap tarball artifact, in order to preserve file perms
mkdir -p $REPO/.build/linux/snap-tarball
SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-$VSCODE_ARCH.tar.gz"
rm -rf $SNAP_TARBALL_PATH
(cd .build/linux && tar -czf $SNAP_TARBALL_PATH snap)

View File

@@ -46,4 +46,5 @@ steps:
# Publish snap package # Publish snap package
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-$ARCH" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH" node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-$ARCH" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH"

View File

@@ -63,17 +63,3 @@ jobs:
vmImage: macOS 10.13 vmImage: macOS 10.13
steps: steps:
- template: darwin/product-build-darwin.yml - template: darwin/product-build-darwin.yml
- job: Mooncake
pool:
vmImage: 'Ubuntu-16.04'
condition: true
dependsOn:
- Windows
- Windows32
- Linux
- LinuxSnap
- Linux32
- macOS
steps:
- template: sync-mooncake.yml

View File

@@ -1,18 +0,0 @@
steps:
- task: NodeTool@0
inputs:
versionSpec: "10.15.1"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs:
versionSpec: "1.10.1"
- script: |
set -e
(cd build ; yarn)
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
node build/azure-pipelines/common/sync-mooncake.js "$VSCODE_QUALITY"

View File

@@ -1,4 +0,0 @@
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min" }
exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" }

View File

@@ -18,47 +18,34 @@ steps:
"machine monacotools.visualstudio.com`npassword $(VSO_PAT)`nmachine github.com`nlogin vscode`npassword $(VSCODE_MIXIN_PASSWORD)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII "machine monacotools.visualstudio.com`npassword $(VSO_PAT)`nmachine github.com`nlogin vscode`npassword $(VSCODE_MIXIN_PASSWORD)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII
$env:npm_config_arch="$(VSCODE_ARCH)" $env:npm_config_arch="$(VSCODE_ARCH)"
$env:CHILD_CONCURRENCY="1" $env:CHILD_CONCURRENCY="1"
$env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)"
exec { git config user.email "vscode@microsoft.com" }
exec { git config user.name "VSCode" }
exec { git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" }
exec { git fetch distro }
exec { git merge $(node -p "require('./package.json').distro") }
exec { yarn } exec { yarn }
exec { yarn gulp mixin } exec { npm run gulp -- mixin }
exec { yarn gulp hygiene } exec { npm run gulp -- hygiene }
exec { yarn monaco-compile-check } exec { npm run monaco-compile-check }
exec { node build/azure-pipelines/common/installDistro.js } exec { node build/azure-pipelines/common/installDistro.js }
exec { node build/lib/builtInExtensions.js } exec { node build/lib/builtInExtensions.js }
displayName: Prepare build
- powershell: | - powershell: |
. build/azure-pipelines/win32/exec.ps1 . build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
$env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" $env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)"
.\build\azure-pipelines\win32\build.ps1 exec { npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-min" }
displayName: Build exec { npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-inno-updater" }
name: build
- powershell: | - powershell: |
. build/azure-pipelines/win32/exec.ps1 . build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
exec { yarn gulp "electron-$(VSCODE_ARCH)" } exec { npm run gulp -- "electron-$(VSCODE_ARCH)" }
exec { .\scripts\test.bat --build --tfs "Unit Tests" } exec { .\scripts\test.bat --build --tfs "Unit Tests" }
# yarn smoketest -- --build "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" # yarn smoketest -- --build "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)"
displayName: Run unit tests name: test
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
exec { yarn gulp "electron-$(VSCODE_ARCH)" }
exec { .\scripts\test-integration.bat --build --tfs "Integration Tests" }
displayName: Run integration tests
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
inputs: inputs:
ConnectedServiceName: 'ESRP CodeSign' ConnectedServiceName: 'ESRP CodeSign'
FolderPath: '$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH),$(agent.builddirectory)/vscode-reh-win32-$(VSCODE_ARCH)' FolderPath: '$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)'
Pattern: '*.dll,*.exe,*.node' Pattern: '*.dll,*.exe,*.node'
signConfigType: inlineSignParams signConfigType: inlineSignParams
inlineOperation: | inlineOperation: |
@@ -132,11 +119,32 @@ steps:
- powershell: | - powershell: |
. build/azure-pipelines/win32/exec.ps1 . build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
exec { npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-archive" "vscode-win32-$(VSCODE_ARCH)-system-setup" "vscode-win32-$(VSCODE_ARCH)-user-setup" --sign }
$Repo = "$(pwd)"
$Root = "$Repo\.."
$SystemExe = "$Repo\.build\win32-$(VSCODE_ARCH)\system-setup\VSCodeSetup.exe"
$UserExe = "$Repo\.build\win32-$(VSCODE_ARCH)\user-setup\VSCodeSetup.exe"
$Zip = "$Repo\.build\win32-$(VSCODE_ARCH)\archive\VSCode-win32-$(VSCODE_ARCH).zip"
$Build = "$Root\VSCode-win32-$(VSCODE_ARCH)"
# get version
$PackageJson = Get-Content -Raw -Path "$Build\resources\app\package.json" | ConvertFrom-Json
$Version = $PackageJson.version
$Quality = "$env:VSCODE_QUALITY"
$env:AZURE_STORAGE_ACCESS_KEY_2 = "$(AZURE_STORAGE_ACCESS_KEY_2)" $env:AZURE_STORAGE_ACCESS_KEY_2 = "$(AZURE_STORAGE_ACCESS_KEY_2)"
$env:MOONCAKE_STORAGE_ACCESS_KEY = "$(MOONCAKE_STORAGE_ACCESS_KEY)"
$env:AZURE_DOCUMENTDB_MASTERKEY = "$(AZURE_DOCUMENTDB_MASTERKEY)" $env:AZURE_DOCUMENTDB_MASTERKEY = "$(AZURE_DOCUMENTDB_MASTERKEY)"
$env:VSCODE_HOCKEYAPP_TOKEN = "$(VSCODE_HOCKEYAPP_TOKEN)"
.\build\azure-pipelines\win32\publish.ps1 $assetPlatform = if ("$(VSCODE_ARCH)" -eq "ia32") { "win32" } else { "win32-x64" }
displayName: Publish
exec { node build/azure-pipelines/common/publish.js $Quality "$global:assetPlatform-archive" archive "VSCode-win32-$(VSCODE_ARCH)-$Version.zip" $Version true $Zip }
exec { node build/azure-pipelines/common/publish.js $Quality "$global:assetPlatform" setup "VSCodeSetup-$(VSCODE_ARCH)-$Version.exe" $Version true $SystemExe }
exec { node build/azure-pipelines/common/publish.js $Quality "$global:assetPlatform-user" setup "VSCodeUserSetup-$(VSCODE_ARCH)-$Version.exe" $Version true $UserExe }
# publish hockeyapp symbols
$hockeyAppId = if ("$(VSCODE_ARCH)" -eq "ia32") { "$(VSCODE_HOCKEYAPP_ID_WIN32)" } else { "$(VSCODE_HOCKEYAPP_ID_WIN64)" }
exec { node build/azure-pipelines/common/symbols.js "$(VSCODE_MIXIN_PASSWORD)" "$(VSCODE_HOCKEYAPP_TOKEN)" "$(VSCODE_ARCH)" $hockeyAppId }
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
displayName: 'Component Detection' displayName: 'Component Detection'

View File

@@ -1,28 +0,0 @@
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
$Arch = "$env:VSCODE_ARCH"
exec { yarn gulp "vscode-win32-$Arch-archive" "vscode-win32-$Arch-system-setup" "vscode-win32-$Arch-user-setup" --sign }
$Repo = "$(pwd)"
$Root = "$Repo\.."
$SystemExe = "$Repo\.build\win32-$Arch\system-setup\VSCodeSetup.exe"
$UserExe = "$Repo\.build\win32-$Arch\user-setup\VSCodeSetup.exe"
$Zip = "$Repo\.build\win32-$Arch\archive\VSCode-win32-$Arch.zip"
$Build = "$Root\VSCode-win32-$Arch"
# get version
$PackageJson = Get-Content -Raw -Path "$Build\resources\app\package.json" | ConvertFrom-Json
$Version = $PackageJson.version
$Quality = "$env:VSCODE_QUALITY"
$AssetPlatform = if ("$Arch" -eq "ia32") { "win32" } else { "win32-x64" }
exec { node build/azure-pipelines/common/publish.js $Quality "$AssetPlatform-archive" archive "VSCode-win32-$Arch-$Version.zip" $Version true $Zip }
exec { node build/azure-pipelines/common/publish.js $Quality "$AssetPlatform" setup "VSCodeSetup-$Arch-$Version.exe" $Version true $SystemExe }
exec { node build/azure-pipelines/common/publish.js $Quality "$AssetPlatform-user" setup "VSCodeUserSetup-$Arch-$Version.exe" $Version true $UserExe }
# publish hockeyapp symbols
$hockeyAppId = if ("$Arch" -eq "ia32") { "$env:VSCODE_HOCKEYAPP_ID_WIN32" } else { "$env:VSCODE_HOCKEYAPP_ID_WIN64" }
exec { node build/azure-pipelines/common/symbols.js "$env:VSCODE_MIXIN_PASSWORD" "$env:VSCODE_HOCKEYAPP_TOKEN" "$Arch" $hockeyAppId }

View File

@@ -87,16 +87,9 @@ const indentationFilter = [
'!build/azure-pipelines/**/*.js', '!build/azure-pipelines/**/*.js',
'!build/azure-pipelines/**/*.config', '!build/azure-pipelines/**/*.config',
'!**/Dockerfile', '!**/Dockerfile',
'!**/Dockerfile.*',
'!**/*.Dockerfile', '!**/*.Dockerfile',
'!**/*.dockerfile', '!**/*.dockerfile',
'!extensions/markdown-language-features/media/*.js', '!extensions/markdown-language-features/media/*.js'
// {{SQL CARBON EDIT}}
'!**/*.xlf',
'!**/*.docx',
'!**/*.sql',
'!extensions/mssql/sqltoolsservice/**',
'!extensions/import/flatfileimportservice/**',
]; ];
const copyrightFilter = [ const copyrightFilter = [
@@ -125,37 +118,7 @@ const copyrightFilter = [
'!resources/completions/**', '!resources/completions/**',
'!extensions/markdown-language-features/media/highlight.css', '!extensions/markdown-language-features/media/highlight.css',
'!extensions/html-language-features/server/src/modes/typescript/*', '!extensions/html-language-features/server/src/modes/typescript/*',
'!extensions/*/server/bin/*', '!extensions/*/server/bin/*'
// {{SQL CARBON EDIT}}
'!extensions/notebook/src/intellisense/text.ts',
'!extensions/mssql/src/objectExplorerNodeProvider/webhdfs.ts',
'!src/sql/workbench/parts/notebook/outputs/tableRenderers.ts',
'!src/sql/workbench/parts/notebook/outputs/common/url.ts',
'!src/sql/workbench/parts/notebook/outputs/common/renderMimeInterfaces.ts',
'!src/sql/workbench/parts/notebook/outputs/common/outputProcessor.ts',
'!src/sql/workbench/parts/notebook/outputs/common/mimemodel.ts',
'!src/sql/workbench/parts/notebook/cellViews/media/*.css',
'!src/sql/base/browser/ui/table/plugins/rowSelectionModel.plugin.ts',
'!src/sql/base/browser/ui/table/plugins/rowDetailView.ts',
'!src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts',
'!src/sql/base/browser/ui/table/plugins/checkboxSelectColumn.plugin.ts',
'!src/sql/base/browser/ui/table/plugins/cellSelectionModel.plugin.ts',
'!src/sql/base/browser/ui/table/plugins/autoSizeColumns.plugin.ts',
'!src/sql/workbench/parts/notebook/outputs/sanitizer.ts',
'!src/sql/workbench/parts/notebook/outputs/renderers.ts',
'!src/sql/workbench/parts/notebook/outputs/registry.ts',
'!src/sql/workbench/parts/notebook/outputs/factories.ts',
'!src/sql/workbench/parts/notebook/models/nbformat.ts',
'!extensions/markdown-language-features/media/tomorrow.css',
'!src/sql/workbench/electron-browser/modelComponents/media/highlight.css',
'!src/sql/parts/modelComponents/highlight.css',
'!extensions/mssql/sqltoolsservice/**',
'!extensions/import/flatfileimportservice/**',
'!extensions/notebook/src/prompts/**',
'!extensions/mssql/src/prompts/**',
'!extensions/notebook/resources/jupyter_config/**',
'!**/*.gif',
'!**/*.xlf'
]; ];
const eslintFilter = [ const eslintFilter = [
@@ -201,7 +164,8 @@ gulp.task('eslint', () => {
}); });
gulp.task('tslint', () => { gulp.task('tslint', () => {
const options = { emitError: true }; // {{SQL CARBON EDIT}}
const options = { emitError: false };
return vfs.src(all, { base: '.', follow: true, allowEmpty: true }) return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
.pipe(filter(tslintFilter)) .pipe(filter(tslintFilter))
@@ -299,8 +263,9 @@ function hygiene(some) {
.pipe(filter(f => !f.stat.isDirectory())) .pipe(filter(f => !f.stat.isDirectory()))
.pipe(filter(indentationFilter)) .pipe(filter(indentationFilter))
.pipe(indentation) .pipe(indentation)
.pipe(filter(copyrightFilter)) .pipe(filter(copyrightFilter));
.pipe(copyrights); // {{SQL CARBON EDIT}}
// .pipe(copyrights);
const typescript = result const typescript = result
.pipe(filter(tslintFilter)) .pipe(filter(tslintFilter))
@@ -310,38 +275,15 @@ function hygiene(some) {
const javascript = result const javascript = result
.pipe(filter(eslintFilter)) .pipe(filter(eslintFilter))
.pipe(gulpeslint('src/.eslintrc')) .pipe(gulpeslint('src/.eslintrc'))
.pipe(gulpeslint.formatEach('compact')) .pipe(gulpeslint.formatEach('compact'));
.pipe(gulpeslint.failAfterError()); // {{SQL CARBON EDIT}}
// .pipe(gulpeslint.failAfterError());
let count = 0; let count = 0;
return es.merge(typescript, javascript) return es.merge(typescript, javascript)
.pipe(es.through(function (data) { .pipe(es.through(function (data) {
count++; // {{SQL CARBON EDIT}}
if (process.env['TRAVIS'] && count % 10 === 0) {
process.stdout.write('.');
}
this.emit('data', data);
}, function () {
process.stdout.write('\n');
const tslintResult = tsLinter.getResult();
if (tslintResult.failures.length > 0) {
for (const failure of tslintResult.failures) {
const name = failure.getFileName();
const position = failure.getStartPosition();
const line = position.getLineAndCharacter().line;
const character = position.getLineAndCharacter().character;
console.error(`${name}:${line + 1}:${character + 1}:${failure.getFailure()}`);
}
errorCount += tslintResult.failures.length;
}
if (errorCount > 0) {
this.emit('error', 'Hygiene failed with ' + errorCount + ' errors. Check \'build/gulpfile.hygiene.js\'.');
} else {
this.emit('end'); this.emit('end');
}
})); }));
} }

View File

@@ -6,6 +6,15 @@
'use strict'; 'use strict';
const gulp = require('gulp'); const gulp = require('gulp');
const json = require('gulp-json-editor');
const buffer = require('gulp-buffer');
const filter = require('gulp-filter');
const es = require('event-stream');
const vfs = require('vinyl-fs');
const pkg = require('../package.json');
const cp = require('child_process');
const fancyLog = require('fancy-log');
const ansiColors = require('ansi-colors');
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
const jeditor = require('gulp-json-editor'); const jeditor = require('gulp-json-editor');

View File

@@ -28,6 +28,7 @@ const formatFiles = (some) => {
console.info('ran formatting on file ' + file.path + ' result: ' + result.message); console.info('ran formatting on file ' + file.path + ' result: ' + result.message);
if (result.error) { if (result.error) {
console.error(result.message); console.error(result.message);
errorCount++;
} }
cb(null, file); cb(null, file);
@@ -39,7 +40,7 @@ const formatFiles = (some) => {
.pipe(filter(f => !f.stat.isDirectory())) .pipe(filter(f => !f.stat.isDirectory()))
.pipe(formatting); .pipe(formatting);
}; }
const formatStagedFiles = () => { const formatStagedFiles = () => {
const cp = require('child_process'); const cp = require('child_process');
@@ -80,4 +81,4 @@ const formatStagedFiles = () => {
process.exit(1); process.exit(1);
}); });
}); });
}; }

View File

@@ -33,10 +33,12 @@ const i18n = require('./lib/i18n');
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
const serviceDownloader = require('service-downloader').ServiceDownloadProvider; const serviceDownloader = require('service-downloader').ServiceDownloadProvider;
const platformInfo = require('service-downloader/out/platform').PlatformInformation; const platformInfo = require('service-downloader/out/platform').PlatformInformation;
const glob = require('glob');
// {{SQL CARBON EDIT}} - End // {{SQL CARBON EDIT}} - End
const deps = require('./dependencies'); const deps = require('./dependencies');
const getElectronVersion = require('./lib/electron').getElectronVersion; const getElectronVersion = require('./lib/electron').getElectronVersion;
const createAsar = require('./lib/asar').createAsar; const createAsar = require('./lib/asar').createAsar;
const minimist = require('minimist');
const { compileBuildTask } = require('./gulpfile.compile'); const { compileBuildTask } = require('./gulpfile.compile');
const productionDependencies = deps.getProductionDependencies(path.dirname(__dirname)); const productionDependencies = deps.getProductionDependencies(path.dirname(__dirname));
@@ -52,7 +54,7 @@ const nodeModules = [
'rxjs/Observable', 'rxjs/Observable',
'rxjs/Subject', 'rxjs/Subject',
'rxjs/Observer', 'rxjs/Observer',
'ng2-charts'] 'ng2-charts/ng2-charts']
.concat(Object.keys(product.dependencies || {})) .concat(Object.keys(product.dependencies || {}))
.concat(_.uniq(productionDependencies.map(d => d.name))) .concat(_.uniq(productionDependencies.map(d => d.name)))
.concat(baseModules); .concat(baseModules);
@@ -75,16 +77,14 @@ const vscodeResources = [
'out-build/bootstrap-window.js', 'out-build/bootstrap-window.js',
'out-build/paths.js', 'out-build/paths.js',
'out-build/vs/**/*.{svg,png,cur,html}', 'out-build/vs/**/*.{svg,png,cur,html}',
'!out-build/vs/code/browser/**/*.html',
'out-build/vs/base/common/performance.js', 'out-build/vs/base/common/performance.js',
'out-build/vs/base/node/languagePacks.js', 'out-build/vs/base/node/languagePacks.js',
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.sh}', 'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh}',
'out-build/vs/base/browser/ui/octiconLabel/octicons/**', 'out-build/vs/base/browser/ui/octiconLabel/octicons/**',
'out-build/vs/workbench/browser/media/*-theme.css', 'out-build/vs/workbench/browser/media/*-theme.css',
'out-build/vs/workbench/contrib/debug/**/*.json', 'out-build/vs/workbench/contrib/debug/**/*.json',
'out-build/vs/workbench/contrib/externalTerminal/**/*.scpt', 'out-build/vs/workbench/contrib/externalTerminal/**/*.scpt',
'out-build/vs/workbench/contrib/webview/browser/pre/*.js', 'out-build/vs/workbench/contrib/webview/electron-browser/webview-pre.js',
'out-build/vs/workbench/contrib/webview/electron-browser/pre/*.js',
'out-build/vs/**/markdown.css', 'out-build/vs/**/markdown.css',
'out-build/vs/workbench/contrib/tasks/**/*.json', 'out-build/vs/workbench/contrib/tasks/**/*.json',
'out-build/vs/workbench/contrib/welcome/walkThrough/**/*.md', 'out-build/vs/workbench/contrib/welcome/walkThrough/**/*.md',
@@ -102,11 +102,13 @@ const vscodeResources = [
'out-build/sql/parts/admin/**/*.html', 'out-build/sql/parts/admin/**/*.html',
'out-build/sql/parts/connection/connectionDialog/media/*.{gif,png,svg}', 'out-build/sql/parts/connection/connectionDialog/media/*.{gif,png,svg}',
'out-build/sql/parts/common/dblist/**/*.html', 'out-build/sql/parts/common/dblist/**/*.html',
'out-build/sql/workbench/parts/dashboard/**/*.html', 'out-build/sql/parts/dashboard/**/*.html',
'out-build/sql/parts/disasterRecovery/**/*.html', 'out-build/sql/parts/disasterRecovery/**/*.html',
'out-build/sql/parts/common/modal/media/**', 'out-build/sql/parts/common/modal/media/**',
'out-build/sql/workbench/parts/grid/media/**', 'out-build/sql/parts/grid/load/lib/**',
'out-build/sql/workbench/parts/grid/views/**/*.html', 'out-build/sql/parts/grid/load/loadJquery.js',
'out-build/sql/parts/grid/media/**',
'out-build/sql/parts/grid/views/**/*.html',
'out-build/sql/parts/tasks/**/*.html', 'out-build/sql/parts/tasks/**/*.html',
'out-build/sql/parts/taskHistory/viewlet/media/**', 'out-build/sql/parts/taskHistory/viewlet/media/**',
'out-build/sql/parts/jobManagement/common/media/*.svg', 'out-build/sql/parts/jobManagement/common/media/*.svg',
@@ -357,7 +359,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
.pipe(util.cleanNodeModule('core-js', ['**/**'], undefined)) .pipe(util.cleanNodeModule('core-js', ['**/**'], undefined))
.pipe(util.cleanNodeModule('slickgrid', ['node_modules/**', 'examples/**'], undefined)) .pipe(util.cleanNodeModule('slickgrid', ['node_modules/**', 'examples/**'], undefined))
.pipe(util.cleanNodeModule('nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['**/*.node', '**/*.a'])) .pipe(util.cleanNodeModule('nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['**/*.node', '**/*.a']))
.pipe(util.cleanNodeModule('vscode-nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['build/Release/*.node', '**/*.a'])) .pipe(util.cleanNodeModule('vscode-nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['**/*.node', '**/*.a']))
// {{SQL CARBON EDIT}} - End // {{SQL CARBON EDIT}} - End
.pipe(util.cleanNodeModule('vsda', ['binding.gyp', 'README.md', 'build/**', '*.bat', '*.sh', '*.cpp', '*.h'], ['build/Release/vsda.node'])) .pipe(util.cleanNodeModule('vsda', ['binding.gyp', 'README.md', 'build/**', '*.bat', '*.sh', '*.cpp', '*.h'], ['build/Release/vsda.node']))
.pipe(util.cleanNodeModule('vscode-windows-ca-certs', ['**/*'], ['package.json', '**/*.node'])) .pipe(util.cleanNodeModule('vscode-windows-ca-certs', ['**/*'], ['package.json', '**/*.node']))
@@ -424,18 +426,14 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
result = es.merge(result, gulp.src('resources/win32/bin/code.sh', { base: 'resources/win32' }) result = es.merge(result, gulp.src('resources/win32/bin/code.sh', { base: 'resources/win32' })
.pipe(replace('@@NAME@@', product.nameShort)) .pipe(replace('@@NAME@@', product.nameShort))
.pipe(replace('@@PRODNAME@@', product.nameLong))
.pipe(replace('@@VERSION@@', version))
.pipe(replace('@@COMMIT@@', commit)) .pipe(replace('@@COMMIT@@', commit))
.pipe(replace('@@APPNAME@@', product.applicationName)) .pipe(replace('@@APPNAME@@', product.applicationName))
.pipe(replace('@@QUALITY@@', quality))
.pipe(rename(function (f) { f.basename = product.applicationName; f.extname = ''; }))); .pipe(rename(function (f) { f.basename = product.applicationName; f.extname = ''; })));
result = es.merge(result, gulp.src('resources/win32/VisualElementsManifest.xml', { base: 'resources/win32' }) result = es.merge(result, gulp.src('resources/win32/VisualElementsManifest.xml', { base: 'resources/win32' })
.pipe(rename(product.nameShort + '.VisualElementsManifest.xml'))); .pipe(rename(product.nameShort + '.VisualElementsManifest.xml')));
} else if (platform === 'linux') { } else if (platform === 'linux') {
result = es.merge(result, gulp.src('resources/linux/bin/code.sh', { base: '.' }) result = es.merge(result, gulp.src('resources/linux/bin/code.sh', { base: '.' })
.pipe(replace('@@PRODNAME@@', product.nameLong))
.pipe(replace('@@NAME@@', product.applicationName)) .pipe(replace('@@NAME@@', product.applicationName))
.pipe(rename('bin/' + product.applicationName))); .pipe(rename('bin/' + product.applicationName)));
} }
@@ -479,6 +477,8 @@ BUILD_TARGETS.forEach(buildTarget => {
minified ? minifyVSCodeTask : optimizeVSCodeTask, minified ? minifyVSCodeTask : optimizeVSCodeTask,
util.rimraf(path.join(buildRoot, destinationFolderName)) util.rimraf(path.join(buildRoot, destinationFolderName))
), ),
ext.packageExtensionTask('mssql', platform, arch),
ext.packageExtensionTask('azurecore', platform, arch),
packageTask(platform, arch, sourceFolderName, destinationFolderName, opts) packageTask(platform, arch, sourceFolderName, destinationFolderName, opts)
)); ));
gulp.task(vscodeTask); gulp.task(vscodeTask);

View File

@@ -27,7 +27,7 @@ const zipPath = arch => path.join(zipDir(arch), `VSCode-win32-${arch}.zip`);
const setupDir = (arch, target) => path.join(repoPath, '.build', `win32-${arch}`, `${target}-setup`); const setupDir = (arch, target) => path.join(repoPath, '.build', `win32-${arch}`, `${target}-setup`);
const issPath = path.join(__dirname, 'win32', 'code.iss'); const issPath = path.join(__dirname, 'win32', 'code.iss');
const innoSetupPath = path.join(path.dirname(path.dirname(require.resolve('innosetup-compiler'))), 'bin', 'ISCC.exe'); const innoSetupPath = path.join(path.dirname(path.dirname(require.resolve('innosetup-compiler'))), 'bin', 'ISCC.exe');
// const signPS1 = path.join(repoPath, 'build', 'azure-pipelines', 'win32', 'sign.ps1'); const signPS1 = path.join(repoPath, 'build', 'azure-pipelines', 'win32', 'sign.ps1');
function packageInnoSetup(iss, options, cb) { function packageInnoSetup(iss, options, cb) {
options = options || {}; options = options || {};

View File

@@ -237,7 +237,6 @@ exports.fromMarketplace = fromMarketplace;
const excludedExtensions = [ const excludedExtensions = [
'vscode-api-tests', 'vscode-api-tests',
'vscode-colorize-tests', 'vscode-colorize-tests',
'vscode-test-resolver',
'ms-vscode.node-debug', 'ms-vscode.node-debug',
'ms-vscode.node-debug2', 'ms-vscode.node-debug2',
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
@@ -253,10 +252,9 @@ const sqlBuiltInExtensions = [
'profiler', 'profiler',
'admin-pack', 'admin-pack',
'big-data-cluster', 'big-data-cluster',
'dacpac', 'dacpac'
'schema-compare',
'cms'
]; ];
var azureExtensions = ['azurecore', 'mssql'];
const builtInExtensions = require('../builtInExtensions.json'); const builtInExtensions = require('../builtInExtensions.json');
/** /**
* We're doing way too much stuff at once, with webpack et al. So much stuff * We're doing way too much stuff at once, with webpack et al. So much stuff
@@ -292,7 +290,8 @@ function packageExtensionsStream(optsIn) {
.filter(({ name }) => opts.desiredExtensions ? opts.desiredExtensions.indexOf(name) >= 0 : true) .filter(({ name }) => opts.desiredExtensions ? opts.desiredExtensions.indexOf(name) >= 0 : true)
.filter(({ name }) => builtInExtensions.every(b => b.name !== name)) .filter(({ name }) => builtInExtensions.every(b => b.name !== name))
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
.filter(({ name }) => sqlBuiltInExtensions.indexOf(name) === -1); .filter(({ name }) => sqlBuiltInExtensions.indexOf(name) === -1)
.filter(({ name }) => azureExtensions.indexOf(name) === -1);
const localExtensions = () => sequence([...localExtensionDescriptions.map(extension => () => { const localExtensions = () => sequence([...localExtensionDescriptions.map(extension => () => {
return fromLocal(extension.path, opts.sourceMappingURLBase) return fromLocal(extension.path, opts.sourceMappingURLBase)
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));

View File

@@ -283,7 +283,6 @@ interface IPackageExtensionsOptions {
const excludedExtensions = [ const excludedExtensions = [
'vscode-api-tests', 'vscode-api-tests',
'vscode-colorize-tests', 'vscode-colorize-tests',
'vscode-test-resolver',
'ms-vscode.node-debug', 'ms-vscode.node-debug',
'ms-vscode.node-debug2', 'ms-vscode.node-debug2',
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
@@ -300,10 +299,9 @@ const sqlBuiltInExtensions = [
'profiler', 'profiler',
'admin-pack', 'admin-pack',
'big-data-cluster', 'big-data-cluster',
'dacpac', 'dacpac'
'schema-compare',
'cms'
]; ];
var azureExtensions = ['azurecore', 'mssql'];
// {{SQL CARBON EDIT}} - End // {{SQL CARBON EDIT}} - End
interface IBuiltInExtension { interface IBuiltInExtension {
@@ -352,7 +350,8 @@ export function packageExtensionsStream(optsIn?: IPackageExtensionsOptions): Nod
.filter(({ name }) => opts.desiredExtensions ? opts.desiredExtensions.indexOf(name) >= 0 : true) .filter(({ name }) => opts.desiredExtensions ? opts.desiredExtensions.indexOf(name) >= 0 : true)
.filter(({ name }) => builtInExtensions.every(b => b.name !== name)) .filter(({ name }) => builtInExtensions.every(b => b.name !== name))
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
.filter(({ name }) => sqlBuiltInExtensions.indexOf(name) === -1); .filter(({ name }) => sqlBuiltInExtensions.indexOf(name) === -1)
.filter(({ name }) => azureExtensions.indexOf(name) === -1);
const localExtensions = () => sequence([...localExtensionDescriptions.map(extension => () => { const localExtensions = () => sequence([...localExtensionDescriptions.map(extension => () => {
return fromLocal(extension.path, opts.sourceMappingURLBase) return fromLocal(extension.path, opts.sourceMappingURLBase)

View File

@@ -222,6 +222,10 @@
"name": "vs/workbench/services/files", "name": "vs/workbench/services/files",
"project": "vscode-workbench" "project": "vscode-workbench"
}, },
{
"name": "vs/workbench/services/files2",
"project": "vscode-workbench"
},
{ {
"name": "vs/workbench/services/integrity", "name": "vs/workbench/services/integrity",
"project": "vscode-workbench" "project": "vscode-workbench"

View File

@@ -24,7 +24,7 @@ function log(message: any, ...rest: any[]): void {
} }
export interface Language { export interface Language {
id: string; // language id, e.g. zh-tw, de id: string; // laguage id, e.g. zh-tw, de
translationId?: string; // language id used in translation tools, e.g zh-hant, de (optional, if not set, the id is used) translationId?: string; // language id used in translation tools, e.g zh-hant, de (optional, if not set, the id is used)
folderName?: string; // language specific folder name, e.g. cht, deu (optional, if not set, the id is used) folderName?: string; // language specific folder name, e.g. cht, deu (optional, if not set, the id is used)
} }

View File

@@ -32,7 +32,7 @@ async function _doExecute(task) {
// Always invoke as if it were a callback task // Always invoke as if it were a callback task
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (task.length === 1) { if (task.length === 1) {
// this is a callback task // this is a calback task
task((err) => { task((err) => {
if (err) { if (err) {
return reject(err); return reject(err);

View File

@@ -54,7 +54,7 @@ async function _doExecute(task: Task): Promise<void> {
// Always invoke as if it were a callback task // Always invoke as if it were a callback task
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (task.length === 1) { if (task.length === 1) {
// this is a callback task // this is a calback task
task((err) => { task((err) => {
if (err) { if (err) {
return reject(err); return reject(err);

View File

@@ -1,7 +1,7 @@
"use strict"; "use strict";
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const ts = require("typescript"); const ts = require("typescript");

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as ts from 'typescript'; import * as ts from 'typescript';

View File

@@ -74,7 +74,7 @@ function update(options) {
let translationPaths = []; let translationPaths = [];
i18n.pullI18nPackFiles(server, userName, apiToken, { id: languageId }, translationPaths) i18n.pullI18nPackFiles(server, userName, apiToken, { id: languageId }, translationPaths)
.on('error', (error) => { .on('error', (error) => {
console.log(`Error occurred while importing translations:`); console.log(`Error occured while importing translations:`);
translationPaths = undefined; translationPaths = undefined;
if (Array.isArray(error)) { if (Array.isArray(error)) {
error.forEach(console.log); error.forEach(console.log);
@@ -100,7 +100,7 @@ function update(options) {
gulp.src(path.join(location, languageId, '**', '*.xlf')) gulp.src(path.join(location, languageId, '**', '*.xlf'))
.pipe(i18n.prepareI18nPackFiles(i18n.externalExtensionsWithTranslations, translationPaths, languageId === 'ps')) .pipe(i18n.prepareI18nPackFiles(i18n.externalExtensionsWithTranslations, translationPaths, languageId === 'ps'))
.on('error', (error) => { .on('error', (error) => {
console.log(`Error occurred while importing translations:`); console.log(`Error occured while importing translations:`);
translationPaths = undefined; translationPaths = undefined;
if (Array.isArray(error)) { if (Array.isArray(error)) {
error.forEach(console.log); error.forEach(console.log);

View File

@@ -43,7 +43,7 @@
"request": "^2.85.0", "request": "^2.85.0",
"tslint": "^5.9.1", "tslint": "^5.9.1",
"service-downloader": "github:anthonydresser/service-downloader#0.1.5", "service-downloader": "github:anthonydresser/service-downloader#0.1.5",
"typescript": "3.4.5", "typescript": "3.3.1",
"vsce": "1.48.0", "vsce": "1.48.0",
"xml2js": "^0.4.17" "xml2js": "^0.4.17"
}, },

View File

@@ -8,7 +8,7 @@
"resolveJsonModule": true, "resolveJsonModule": true,
"experimentalDecorators": true, "experimentalDecorators": true,
// enable JavaScript type checking for the language service // enable JavaScript type checking for the language service
// use the tsconfig.build.json for compiling which disable JavaScript // use the tsconfig.build.json for compiling wich disable JavaScript
// type checking so that JavaScript file are not transpiled // type checking so that JavaScript file are not transpiled
"allowJs": true, "allowJs": true,
"checkJs": true, "checkJs": true,

View File

@@ -70,7 +70,7 @@ Type: files; Name: "{app}\resources\app\Credits_45.0.2454.85.html"; Check: IsNot
Type: filesandordirs; Name: "{app}\_" Type: filesandordirs; Name: "{app}\_"
[Tasks] [Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce; Check: IsNotUpdate
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1 Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
Name: "associatewithfiles"; Description: "{cm:AssociateWithFiles,{#NameLong}}"; GroupDescription: "{cm:Other}"; Flags: unchecked Name: "associatewithfiles"; Description: "{cm:AssociateWithFiles,{#NameLong}}"; GroupDescription: "{cm:Other}"; Flags: unchecked
Name: "addtopath"; Description: "{cm:AddToPath}"; GroupDescription: "{cm:Other}" Name: "addtopath"; Description: "{cm:AddToPath}"; GroupDescription: "{cm:Other}"

View File

@@ -3201,10 +3201,10 @@ typed-rest-client@^0.9.0:
tunnel "0.0.4" tunnel "0.0.4"
underscore "1.8.3" underscore "1.8.3"
typescript@3.4.5: typescript@3.3.1:
version "3.4.5" version "3.3.1"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.1.tgz#6de14e1db4b8a006ac535e482c8ba018c55f750b"
integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw== integrity sha512-cTmIDFW7O0IHbn1DPYjkiebHxwtCMU+eTy30ZtJNBPF9j2O1ITu5XH2YnBeVRKWHqF+3JQwWJv0Q0aUgX8W7IA==
uc.micro@^1.0.1, uc.micro@^1.0.5: uc.micro@^1.0.1, uc.micro@^1.0.5:
version "1.0.5" version "1.0.5"

View File

@@ -73,12 +73,12 @@
"git": { "git": {
"name": "electron", "name": "electron",
"repositoryUrl": "https://github.com/electron/electron", "repositoryUrl": "https://github.com/electron/electron",
"commitHash": "e84a6860e35e14b4031b88bb9b49841cdb89a305" "commitHash": "73158a6419a3e2da9e4d523e1131052abd28fbbb"
} }
}, },
"isOnlyProductionDependency": true, "isOnlyProductionDependency": true,
"license": "MIT", "license": "MIT",
"version": "3.1.8" "version": "3.1.6"
}, },
{ {
"component": { "component": {
@@ -111,11 +111,11 @@
"git": { "git": {
"name": "vscode-octicons-font", "name": "vscode-octicons-font",
"repositoryUrl": "https://github.com/Microsoft/vscode-octicons-font", "repositoryUrl": "https://github.com/Microsoft/vscode-octicons-font",
"commitHash": "4f69de3a233ed501c2098e33047e116ac2fbbf42" "commitHash": "5095860bb929919670646e2dfa0ee47d9b93bcb9"
} }
}, },
"license": "MIT", "license": "MIT",
"version": "1.1.0" "version": "1.0.0"
}, },
{ {
"component": { "component": {

View File

@@ -1,7 +1,7 @@
{ {
"name": "admin-tool-ext-win", "name": "admin-tool-ext-win",
"displayName": "%adminToolExtWin.displayName%", "displayName": "Database Admin Tool Extensions for Windows",
"description": "%adminToolExtWin.description%", "description": "Adds additional Windows-specific functionality to Azure Data Studio",
"version": "0.0.1", "version": "0.0.1",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
@@ -26,37 +26,23 @@
"contributes": { "contributes": {
"commands": [ "commands": [
{ {
"command": "adminToolExtWin.launchSsmsMinPropertiesDialog", "command": "adminToolExtWin.launchSsmsServerPropertiesDialog",
"title": "%adminToolExtWin.propertiesMenuItem%", "title": "%adminToolExtWin.launchSsmsServerPropertiesDialog%",
"category": "AdminToolExtWin"
},
{
"command": "adminToolExtWin.launchSsmsMinGswDialog",
"title": "%adminToolExtWin.launchGswMenuItem%",
"category": "AdminToolExtWin" "category": "AdminToolExtWin"
} }
], ],
"menus": { "menus": {
"commandPalette": [ "commandPalette": [
{ {
"command": "adminToolExtWin.launchSsmsMinPropertiesDialog", "command": "adminToolExtWin.launchSsmsServerPropertiesDialog",
"when": "false"
},
{
"command": "adminToolExtWin.launchSsmsMinGswDialog",
"when": "false" "when": "false"
} }
], ],
"objectExplorer/item/context": [ "objectExplorer/item/context": [
{ {
"command": "adminToolExtWin.launchSsmsMinGswDialog", "command": "adminToolExtWin.launchSsmsServerPropertiesDialog",
"when": "isWindows && connectionProvider == MSSQL && nodeType && nodeType == Database", "when": "isWindows && connectionProvider == MSSQL && nodeType && nodeType == Server",
"group": "z-AdminToolExt@1" "group": "AdminToolExtWin"
},
{
"command": "adminToolExtWin.launchSsmsMinPropertiesDialog",
"when": "isWindows && connectionProvider == MSSQL && nodeType && nodeType =~ /^(Server|Database|Table|Column|Index|Statistic|View|ServerLevelLogin|ServerLevelServerRole|ServerLevelCredential|ServerLevelServerAudit|ServerLevelServerAuditSpecification|StoredProcedure|ScalarValuedFunction|TableValuedFunction|AggregateFunction|Synonym|Assembly|UserDefinedDataType|UserDefinedType|UserDefinedTableType|Sequence|User|DatabaseRole|ApplicationRole|Schema|SecurityPolicy|ServerLevelLinkedServer)$/",
"group": "z-AdminToolExt@2"
} }
] ]
}, },

View File

@@ -1,6 +1,3 @@
{ {
"adminToolExtWin.displayName": "Database Administration Tool Extensions for Windows", "adminToolExtWin.launchSsmsServerPropertiesDialog": "Properties"
"adminToolExtWin.description": "Adds additional Windows-specific functionality to Azure Data Studio",
"adminToolExtWin.propertiesMenuItem": "Properties",
"adminToolExtWin.launchGswMenuItem": "Generate Scripts..."
} }

View File

@@ -1,9 +1,9 @@
{ {
"downloadUrl": "https://sqlopsextensions.blob.core.windows.net/tools/ssmsmin/{#version#}/{#fileName#}", "downloadUrl": "https://sqlopsextensions.blob.core.windows.net/tools/ssmsmin/{#version#}/{#fileName#}",
"version": "15.0.18120.0", "version": "15.0.18092.0",
"downloadFileNames": { "downloadFileNames": {
"Windows_64": "SsmsMin-15.0.18120.0-win-x64.zip", "Windows_64": "SsmsMin-15.0.18092.0-win-x64.zip",
"Windows_86": "SsmsMin-15.0.18120.0-win-x86.zip" "Windows_86": "SsmsMin-15.0.18092.0-win-x86.zip"
}, },
"installDirectory": "ssmsmin/{#platform#}/{#version#}", "installDirectory": "ssmsmin/{#platform#}/{#version#}",
"executableFiles": [ "executableFiles": [

View File

@@ -2,6 +2,8 @@
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
///
'use strict';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import * as path from 'path'; import * as path from 'path';
@@ -9,51 +11,15 @@ import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { IConfig, ServerProvider } from 'service-downloader'; import { IConfig, ServerProvider } from 'service-downloader';
import { Telemetry } from './telemetry'; import { Telemetry } from './telemetry';
import { doubleEscapeSingleQuotes, backEscapeDoubleQuotes, getConfiguration } from './utils'; import * as utils from './utils';
import { ChildProcess, exec } from 'child_process'; import { ChildProcess, exec, ExecException } from 'child_process';
import { stringify } from 'querystring';
const baseConfig = require('./config.json'); const baseConfig = require('./config.json');
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
let exePath: string; let exePath: string;
let runningProcesses: Map<number, ChildProcess> = new Map<number, ChildProcess>(); let runningProcesses: Map<number, ChildProcess> = new Map<number, ChildProcess>();
interface SmoMapping {
action: string;
urnName: string;
}
const nodeTypeToUrnNameMapping: { [oeNodeType: string]: SmoMapping } = {
'Database': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Database', urnName: 'Database' },
'Server': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Server', urnName: 'Server' },
'ServerLevelServerAudit': { action: 'sqla:AuditProperties', urnName: 'Audit' },
'ServerLevelCredential': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Credential', urnName: 'Credential' },
'ServerLevelServerRole': { action: 'sqla:ManageServerRole', urnName: 'Role' },
'ServerLevelServerAuditSpecification': { action: 'sqla:ServerAuditSpecificationProperties', urnName: 'ServerAuditSpecification' },
'ServerLevelLinkedServer': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.LinkedServer', urnName: 'LinkedServer' },
'Table': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Table', urnName: 'Table' },
'View': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.View', urnName: 'View' },
'Column': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Column', urnName: 'Column' },
'Index': { action: 'sqla:IndexProperties', urnName: 'Index' },
'Statistic': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Statistic', urnName: 'Statistic' },
'StoredProcedure': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.StoredProcedure', urnName: 'StoredProcedure' },
'ScalarValuedFunction': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.UserDefinedFunction', urnName: 'UserDefinedFunction' },
'TableValuedFunction': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.UserDefinedFunction', urnName: 'UserDefinedFunction' },
'AggregateFunction': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.UserDefinedFunction', urnName: 'UserDefinedFunction' },
'Synonym': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Synonym', urnName: 'Synonym' },
'Assembly': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.SqlAssembly', urnName: 'SqlAssembly' },
'UserDefinedDataType': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.UserDefinedDataType', urnName: 'UserDefinedDataType' },
'UserDefinedType': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.UserDefinedType', urnName: 'UserDefinedType' },
'UserDefinedTableType': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.UserDefinedTableType', urnName: 'UserDefinedTableType' },
'Sequence': { action: 'sqla:SequenceProperties', urnName: 'Sequence' },
'User': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.User', urnName: 'User' },
'DatabaseRole': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.DatabaseRole', urnName: 'Role' },
'ApplicationRole': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.ApplicationRole', urnName: 'ApplicationRole' },
'Schema': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Schema', urnName: 'Schema' },
'SecurityPolicy': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.SecurityPolicy', urnName: 'SecurityPolicy' },
'ServerLevelLogin': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Login', urnName: 'Login' },
};
// Params to pass to SsmsMin.exe, only an action and server are required - the rest are optional based on the // Params to pass to SsmsMin.exe, only an action and server are required - the rest are optional based on the
// action used. Exported for use in testing. // action used. Exported for use in testing.
export interface LaunchSsmsDialogParams { export interface LaunchSsmsDialogParams {
@@ -61,6 +27,7 @@ export interface LaunchSsmsDialogParams {
server: string; server: string;
database?: string; database?: string;
user?: string; user?: string;
password?: string;
useAad?: boolean; useAad?: boolean;
urn?: string; urn?: string;
} }
@@ -72,8 +39,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
let config: IConfig = JSON.parse(JSON.stringify(baseConfig)); let config: IConfig = JSON.parse(JSON.stringify(baseConfig));
config.installDirectory = path.join(context.extensionPath, config.installDirectory); config.installDirectory = path.join(context.extensionPath, config.installDirectory);
config.proxy = getConfiguration('http').get('proxy'); config.proxy = utils.getConfiguration('http').get('proxy');
config.strictSSL = getConfiguration('http').get('proxyStrictSSL') || true; config.strictSSL = utils.getConfiguration('http').get('proxyStrictSSL') || true;
const serverdownloader = new ServerProvider(config); const serverdownloader = new ServerProvider(config);
const installationStart = Date.now(); const installationStart = Date.now();
@@ -88,9 +55,9 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
} else { } else {
throw new Error('Could not find SsmsMin.exe after downloading'); throw new Error('Could not find SsmsMin.exe after downloading');
} }
// Add the command now that we have the exePath to run the tool with
// Register the commands now that we have the exePath to run the tool with context.subscriptions.push(
registerCommands(context); vscode.commands.registerCommand('adminToolExtWin.launchSsmsServerPropertiesDialog', handleLaunchSsmsServerPropertiesDialogCommand));
Telemetry.sendTelemetryEvent('startup/ExtensionStarted', { Telemetry.sendTelemetryEvent('startup/ExtensionStarted', {
installationTime: String(installationComplete - installationStart), installationTime: String(installationComplete - installationStart),
@@ -111,56 +78,16 @@ export async function deactivate(): Promise<void> {
runningProcesses.forEach(p => exec('taskkill /pid ' + p.pid + ' /T /F')); runningProcesses.forEach(p => exec('taskkill /pid ' + p.pid + ' /T /F'));
} }
/**
* Registers extension commands with command subsystem
* @param context The context used to register the commands
*/
function registerCommands(context: vscode.ExtensionContext): void {
context.subscriptions.push(
vscode.commands.registerCommand('adminToolExtWin.launchSsmsMinPropertiesDialog', handleLaunchSsmsMinPropertiesDialogCommand));
context.subscriptions.push(
vscode.commands.registerCommand('adminToolExtWin.launchSsmsMinGswDialog', handleLaunchSsmsMinGswDialogCommand));
}
/** /**
* Handler for command to launch SSMS Server Properties dialog * Handler for command to launch SSMS Server Properties dialog
* @param connectionId The connection context from the command * @param connectionId The connection context from the command
*/ */
async function handleLaunchSsmsMinPropertiesDialogCommand(connectionContext?: azdata.ObjectExplorerContext): Promise<void> { function handleLaunchSsmsServerPropertiesDialogCommand(connectionContext?: azdata.ObjectExplorerContext) {
if (!connectionContext) { if (connectionContext && connectionContext.connectionProfile) {
vscode.window.showErrorMessage(localize('adminToolExtWin.noConnectionContextForProp', 'No ConnectionContext provided for handleLaunchSsmsMinPropertiesDialogCommand'));
return;
}
let nodeType: string;
if (connectionContext.isConnectionNode) {
nodeType = 'Server';
}
else if (connectionContext.nodeInfo) {
nodeType = connectionContext.nodeInfo.nodeType;
}
else {
vscode.window.showErrorMessage(localize('adminToolExtWin.noOeNode', 'Could not determine NodeType for handleLaunchSsmsMinPropertiesDialogCommand with context {0}', JSON.stringify(connectionContext)));
return;
}
launchSsmsDialog( launchSsmsDialog(
nodeTypeToUrnNameMapping[nodeType].action, /*action*/'sqla:Properties@Microsoft.SqlServer.Management.Smo.Server',
connectionContext); /*connectionProfile*/connectionContext.connectionProfile);
}
/**
* Handler for command to launch SSMS "Generate Script Wizard" dialog
* @param connectionId The connection context from the command
*/
async function handleLaunchSsmsMinGswDialogCommand(connectionContext?: azdata.ObjectExplorerContext): Promise<void> {
if (!connectionContext) {
vscode.window.showErrorMessage(localize('adminToolExtWin.noConnectionContextForGsw', 'No ConnectionContext provided for handleLaunchSsmsMinPropertiesDialogCommand'));
} }
launchSsmsDialog(
'GenerateScripts',
connectionContext);
} }
/** /**
@@ -169,72 +96,29 @@ async function handleLaunchSsmsMinGswDialogCommand(connectionContext?: azdata.Ob
* @param params The params used to construct the command * @param params The params used to construct the command
* @param urn The URN to pass to SsmsMin * @param urn The URN to pass to SsmsMin
*/ */
async function launchSsmsDialog(action: string, connectionContext: azdata.ObjectExplorerContext): Promise<void> { function launchSsmsDialog(action: string, connectionProfile: azdata.IConnectionProfile, urn?: string) {
if (!exePath) { if (!exePath) {
vscode.window.showErrorMessage(localize('adminToolExtWin.noExeError', 'Unable to find SsmsMin.exe.')); vscode.window.showErrorMessage(localize('adminToolExtWin.noExeError', 'Unable to find SsmsMin.exe.'));
return; return;
} }
if (!connectionContext.connectionProfile) { Telemetry.sendTelemetryEvent('LaunchSsmsDialog', { 'action': action });
vscode.window.showErrorMessage(localize('adminToolExtWin.noConnectionProfile', 'No connectionProfile provided from connectionContext : {0}', JSON.stringify(connectionContext)));
return;
}
// Currently Azure isn't supported by the SSMS server properties dialog
const serverInfo = await azdata.connection.getServerInfo(connectionContext.connectionProfile.id);
if (serverInfo && serverInfo.isCloud) {
vscode.window.showErrorMessage(localize('adminToolExtWin.invalidEngineType', 'This option is not currently available for this engine type.'));
return;
}
// Note - this is a temporary fix for the issue that currently the connection API doesn't allow retrieving credentials for a disconnected
// node. So until that's fixed we'll prevent users from attempting to launch SsmsMin on a disconnected node.
// We also aren't able to hide the menu item on disconnected nodes because we currently don't have a contextKey for the connected status
// of a node.
const activeConnections = await azdata.connection.getActiveConnections();
if (!activeConnections.some(conn => conn.connectionId === connectionContext.connectionProfile.id)) {
vscode.window.showErrorMessage(localize('adminToolExtWin.notConnected', 'This option requires a connected node - please connect and try again.'));
return;
}
let oeNode: azdata.objectexplorer.ObjectExplorerNode;
// Server node is a Connection node and so doesn't have the NodeInfo
if (connectionContext.isConnectionNode) {
oeNode = undefined;
}
else if (connectionContext.nodeInfo && connectionContext.nodeInfo.nodeType && connectionContext.connectionProfile) {
oeNode = await azdata.objectexplorer.getNode(connectionContext.connectionProfile.id, connectionContext.nodeInfo.nodePath);
}
else {
vscode.window.showErrorMessage(localize('adminToolExtWin.noOENode', 'Could not determine Object Explorer node from connectionContext : {0}', JSON.stringify(connectionContext)));
return;
}
let urn: string = await buildUrn(connectionContext.connectionProfile.serverName, oeNode);
let password: string = connectionContext.connectionProfile.password;
if (!password || password === '') {
let creds = await azdata.connection.getCredentials(connectionContext.connectionProfile.id);
password = creds[azdata.ConnectionOptionSpecialType.password];
}
let params: LaunchSsmsDialogParams = { let params: LaunchSsmsDialogParams = {
action: action, action: action,
server: connectionContext.connectionProfile.serverName, server: connectionProfile.serverName,
database: connectionContext.connectionProfile.databaseName, database: connectionProfile.databaseName,
user: connectionContext.connectionProfile.userName, password: connectionProfile.password,
useAad: connectionContext.connectionProfile.authenticationType === 'AzureMFA', user: connectionProfile.userName,
useAad: connectionProfile.authenticationType === 'AzureMFA',
urn: urn urn: urn
}; };
let args = buildSsmsMinCommandArgs(params); let args = buildSsmsMinCommandArgs(params);
Telemetry.sendTelemetryEvent('LaunchSsmsDialog', { 'action': action });
// This will be an async call since we pass in the callback // This will be an async call since we pass in the callback
let proc: ChildProcess = exec( var proc: ChildProcess = exec(
/*command*/ `"${exePath}" ${args}`, /*command*/`"${exePath}" ${args}`,
/*options*/ undefined, /*options*/undefined,
(execException, stdout, stderr) => { (execException, stdout, stderr) => {
// Process has exited so remove from map of running processes // Process has exited so remove from map of running processes
runningProcesses.delete(proc.pid); runningProcesses.delete(proc.pid);
@@ -244,15 +128,13 @@ async function launchSsmsDialog(action: string, connectionContext: azdata.Object
}); });
let err = stderr.toString(); let err = stderr.toString();
if (err !== '') { if (err !== '') {
vscode.window.showErrorMessage(localize( console.warn(`Error calling SsmsMin with args '${args}' - ${err}`);
'adminToolExtWin.ssmsMinError',
'Error calling SsmsMin with args \'{0}\' - {1}', args, err));
} }
}); });
// If we're not using AAD the tool prompts for a password on stdin // If we're not using AAD the tool prompts for a password on stdin
if (params.useAad !== true) { if (params.useAad !== true) {
proc.stdin.end(password ? password : ''); proc.stdin.end(params.password ? params.password : '');
} }
// Save the process into our map so we can make sure to stop them if we exit before shutting down // Save the process into our map so we can make sure to stop them if we exit before shutting down
@@ -266,34 +148,10 @@ async function launchSsmsDialog(action: string, connectionContext: azdata.Object
* @param params The params used to build up the command parameter string * @param params The params used to build up the command parameter string
*/ */
export function buildSsmsMinCommandArgs(params: LaunchSsmsDialogParams): string { export function buildSsmsMinCommandArgs(params: LaunchSsmsDialogParams): string {
return `${params.action ? '-a "' + backEscapeDoubleQuotes(params.action) + '"' : ''}\ return `${params.action ? '-a "' + params.action.replace(/"/g, '\\"') + '"' : ''}\
${params.server ? ' -S "' + backEscapeDoubleQuotes(params.server) + '"' : ''}\ ${params.server ? ' -S "' + params.server.replace(/"/g, '\\"') + '"' : ''}\
${params.database ? ' -D "' + backEscapeDoubleQuotes(params.database) + '"' : ''}\ ${params.database ? ' -D "' + params.database.replace(/"/g, '\\"') + '"' : ''}\
${params.useAad !== true && params.user ? ' -U "' + backEscapeDoubleQuotes(params.user) + '"' : ''}\ ${params.useAad !== true && params.user ? ' -U "' + params.user.replace(/"/g, '\\"') + '"' : ''}\
${params.useAad === true ? ' -G' : ''}\ ${params.useAad === true ? ' -G' : ''}\
${params.urn ? ' -u "' + backEscapeDoubleQuotes(params.urn) + '"' : ''}`; ${params.urn ? ' -u "' + params.urn.replace(/"/g, '\\"') + '"' : ''}`;
}
/**
* Builds the URN string for a given ObjectExplorerNode in the form understood by SsmsMin
* @param serverName The name of the Server to use for the Server segment
* @param node The node to get the URN of
*/
export async function buildUrn(serverName: string, node: azdata.objectexplorer.ObjectExplorerNode): Promise<string> {
let urnNodes: string[] = [];
while (node) {
// Server is special since it's a connection node - always add it as the root
if (node.nodeType === 'Server') {
break;
}
else if (node.metadata && node.nodeType !== 'Folder') {
// SFC URN expects Name and Schema to be separate properties
let urnSegment = node.metadata.schema && node.metadata.schema !== '' ?
`${nodeTypeToUrnNameMapping[node.nodeType].urnName}[@Name='${doubleEscapeSingleQuotes(node.metadata.name)}' and @Schema='${doubleEscapeSingleQuotes(node.metadata.schema)}']` :
`${nodeTypeToUrnNameMapping[node.nodeType].urnName}[@Name='${doubleEscapeSingleQuotes(node.metadata.name)}']`;
urnNodes = [urnSegment].concat(urnNodes);
}
node = await node.getParent();
}
return [`Server[@Name='${doubleEscapeSingleQuotes(serverName)}']`].concat(urnNodes).join('/');
} }

View File

@@ -1,68 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
/**
* Helper stub class for mocking ExtHostObjectExplorerNode
*/
export class ExtHostObjectExplorerNodeStub implements azdata.objectexplorer.ObjectExplorerNode {
// Stub properties
private parent: azdata.objectexplorer.ObjectExplorerNode;
// Base properties
public connectionId: string;
public nodePath: string;
public nodeType: string;
public nodeSubType: string;
public nodeStatus: string;
public label: string;
public isLeaf: boolean;
public metadata: azdata.ObjectMetadata;
public errorMessage: string;
constructor(nodeName: string, nodeSchema: string, nodeType, parent: azdata.objectexplorer.ObjectExplorerNode) {
this.parent = parent;
this.nodeType = nodeType;
this.metadata = { metadataType: undefined, metadataTypeName: undefined, name: nodeName, schema: nodeSchema, urn: undefined };
}
isExpanded(): Thenable<boolean> {
throw new Error('Method not implemented');
}
setExpandedState(expandedState: vscode.TreeItemCollapsibleState): Thenable<void> {
throw new Error('Method not implemented');
}
setSelected(selected: boolean, clearOtherSelections: boolean = undefined): Thenable<void> {
throw new Error('Method not implemented');
}
getChildren(): Thenable<azdata.objectexplorer.ObjectExplorerNode[]> {
throw new Error('Method not implemented');
}
getParent(): Thenable<azdata.objectexplorer.ObjectExplorerNode> {
return Promise.resolve(this.parent);
}
refresh(): Thenable<void> {
throw new Error('Method not implemented');
}
/**
*
* @param nodeName Helperfunction to create a node that is a child of this one
* @param nodeSchema The schema to give the child node
* @param nodeType The type of node this should be
*/
createChild(nodeName: string, nodeSchema: string, nodeType: string): ExtHostObjectExplorerNodeStub {
return new ExtHostObjectExplorerNodeStub(nodeName, nodeSchema, nodeType, this);
}
}

View File

@@ -8,128 +8,60 @@
import * as should from 'should'; import * as should from 'should';
import 'mocha'; import 'mocha';
import { buildSsmsMinCommandArgs, buildUrn, LaunchSsmsDialogParams } from '../main'; import * as extensionMain from '../main';
import { doubleEscapeSingleQuotes, backEscapeDoubleQuotes } from '../utils';
import { ExtHostObjectExplorerNodeStub } from './stubs';
describe('buildSsmsMinCommandArgs Method Tests', () => { describe('buildSsmsMinCommandArgs Method Tests', () => {
it('Should be built correctly with all params and UseAAD as false', function (): void { it('Should be built correctly with all params and UseAAD as false', function (): void {
const params: LaunchSsmsDialogParams = { let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction', action: 'myAction',
server: 'myServer', server: 'myServer',
database: 'myDatabase', database: 'myDatabase',
user: 'user', user: 'user',
password: 'password',
useAad: false, useAad: false,
urn: 'Server\\Database\\Table' urn: 'Server\\Database\\Table'
}; };
const args = buildSsmsMinCommandArgs(params); let args = extensionMain.buildSsmsMinCommandArgs(params);
should(args).equal('-a "myAction" -S "myServer" -D "myDatabase" -U "user" -u "Server\\Database\\Table"'); should(args).equal('-a "myAction" -S "myServer" -D "myDatabase" -U "user" -u "Server\\Database\\Table"');
}); });
it('Should be built correctly with all params and UseAAD as true', function (): void { it('Should be built correctly with all params and UseAAD as true', function (): void {
const params: LaunchSsmsDialogParams = { let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction', action: 'myAction',
server: 'myServer', server: 'myServer',
database: 'myDatabase', database: 'myDatabase',
user: 'user', user: 'user',
password: 'password',
useAad: true, useAad: true,
urn: 'Server\\Database\\Table' urn: 'Server\\Database\\Table'
}; };
const args = buildSsmsMinCommandArgs(params); let args = extensionMain.buildSsmsMinCommandArgs(params);
// User is omitted since UseAAD is true // User is omitted since UseAAD is true
should(args).equal('-a "myAction" -S "myServer" -D "myDatabase" -G -u "Server\\Database\\Table"'); should(args).equal('-a "myAction" -S "myServer" -D "myDatabase" -G -u "Server\\Database\\Table"');
}); });
it('Should be built correctly and names escaped correctly', function (): void { it('Should be built correctly and names escaped correctly', function (): void {
const params: LaunchSsmsDialogParams = { let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction\'"/\\[]tricky', action: 'myAction\'"/\\[]tricky',
server: 'myServer\'"/\\[]tricky', server: 'myServer\'"/\\[]tricky',
database: 'myDatabase\'"/\\[]tricky', database: 'myDatabase\'"/\\[]tricky',
user: 'user\'"/\\[]tricky', user: 'user\'"/\\[]tricky',
password: 'password',
useAad: true, useAad: true,
urn: 'Server\\Database[\'myDatabase\'\'"/\\[]tricky\']\\Table["myTable\'""/\\[]tricky"]' urn: 'Server\\Database[\'myDatabase\'\'"/\\[]tricky\']\\Table["myTable\'""/\\[]tricky"]'
}; };
const args = buildSsmsMinCommandArgs(params); let args = extensionMain.buildSsmsMinCommandArgs(params);
// User is omitted since UseAAD is true // User is omitted since UseAAD is true
should(args).equal('-a "myAction\'\\"/\\[]tricky" -S "myServer\'\\"/\\[]tricky" -D "myDatabase\'\\"/\\[]tricky" -G -u "Server\\Database[\'myDatabase\'\'\\"/\\[]tricky\']\\Table[\\"myTable\'\\"\\"/\\[]tricky\\"]"'); should(args).equal('-a "myAction\'\\"/\\[]tricky" -S "myServer\'\\"/\\[]tricky" -D "myDatabase\'\\"/\\[]tricky" -G -u "Server\\Database[\'myDatabase\'\'\\"/\\[]tricky\']\\Table[\\"myTable\'\\"\\"/\\[]tricky\\"]"');
}); });
it('Should be built correctly with only action and server', function (): void { it('Should be built correctly with only action and server', function (): void {
const params: LaunchSsmsDialogParams = { let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction', action: 'myAction',
server: 'myServer' server: 'myServer'
}; };
const args = buildSsmsMinCommandArgs(params); let args = extensionMain.buildSsmsMinCommandArgs(params);
should(args).equal('-a "myAction" -S "myServer"'); should(args).equal('-a "myAction" -S "myServer"');
}); });
}); });
const serverName = 'My\'Server';
const escapedServerName = doubleEscapeSingleQuotes(serverName);
const dbName = 'My\'Db';
const escapedDbName = doubleEscapeSingleQuotes(dbName);
const dbSchema = 'db\'sch';
const escapedDbSchema = doubleEscapeSingleQuotes(dbSchema);
const tableName = 'My\'Table';
const escapedTableName = doubleEscapeSingleQuotes(tableName);
const tableSchema = 'tbl\'sch';
const escapedTableSchema = doubleEscapeSingleQuotes(tableSchema);
describe('buildUrn Method Tests', () => {
it('Urn should be correct with just server', async function (): Promise<void> {
should(await buildUrn(serverName, undefined)).equal(`Server[@Name=\'${escapedServerName}\']`);
});
it('Urn should be correct with Server and only Databases folder', async function (): Promise<void> {
const leafNode: ExtHostObjectExplorerNodeStub =
new ExtHostObjectExplorerNodeStub('Databases', undefined, 'Folder', undefined);
should(await buildUrn(serverName, leafNode)).equal(`Server[@Name='${escapedServerName}']`);
});
it('Urn should be correct with Server and Database node', async function (): Promise<void> {
const leafNode: ExtHostObjectExplorerNodeStub =
new ExtHostObjectExplorerNodeStub('Databases', undefined, 'Folder', undefined)
.createChild(dbName, dbSchema, 'Database');
should(await buildUrn(serverName, leafNode)).equal(
`Server[@Name='${escapedServerName}']/Database[@Name='${escapedDbName}' and @Schema='${escapedDbSchema}']`);
});
it('Urn should be correct with Multiple levels of Nodes', async function (): Promise<void> {
const rootNode: ExtHostObjectExplorerNodeStub =
new ExtHostObjectExplorerNodeStub('Databases', undefined, 'Folder', undefined)
.createChild(dbName, dbSchema, 'Database')
.createChild('Tables', undefined, 'Folder')
.createChild(tableName, tableSchema, 'Table');
should(await buildUrn(serverName, rootNode)).equal(
`Server[@Name='${escapedServerName}']/Database[@Name='${escapedDbName}' and @Schema='${escapedDbSchema}']/Table[@Name='${escapedTableName}' and @Schema='${escapedTableSchema}']`);
});
});
describe('doubleEscapeSingleQuotes Method Tests', () => {
it('Should return original string if no single quotes', function (): void {
const testString: string = 'MyTestString';
const ret = doubleEscapeSingleQuotes(testString);
should(ret).equal(testString);
});
it('Should return escaped original string if it contains single quotes', function (): void {
const testString: string = 'MyTestString\'\'WithQuotes';
const ret = doubleEscapeSingleQuotes(testString);
should(ret).equal('MyTestString\'\'\'\'WithQuotes');
});
});
describe('backEscapeDoubleQuotes Method Tests', () => {
it('Should return original string if no double quotes', function (): void {
const testString: string = 'MyTestString';
const ret = backEscapeDoubleQuotes(testString);
should(ret).equal(testString);
});
it('Should return escaped original string if it contains double quotes', function (): void {
const testString: string = 'MyTestString\"\"WithQuotes';
const ret = backEscapeDoubleQuotes(testString);
should(ret).equal('MyTestString\\"\\"WithQuotes');
});
});

View File

@@ -40,21 +40,3 @@ export function getConfiguration(extensionName?: string, resource?: vscode.Uri |
} }
return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri); return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri);
} }
/**
* Escapes all single-quotes (') by prefixing them with another single quote ('')
* ' => ''
* @param value The string to escape
*/
export function doubleEscapeSingleQuotes(value: string): string {
return value.replace(/'/g, '\'\'');
}
/**
* Escape all double-quotes (") by prefixing them with a \
* " => \"
* @param value The string to escape
*/
export function backEscapeDoubleQuotes(value: string): string {
return value.replace(/"/g, '\\"');
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,14 +2,14 @@
"name": "agent", "name": "agent",
"displayName": "SQL Server Agent", "displayName": "SQL Server Agent",
"description": "Manage and troubleshoot SQL Server Agent jobs", "description": "Manage and troubleshoot SQL Server Agent jobs",
"version": "0.39.0", "version": "0.37.0",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": true, "preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt", "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
"icon": "images/sqlserver.png", "icon": "images/sqlserver.png",
"aiKey": "AIF-5574968e-856d-40d2-af67-c89a14e76412", "aiKey": "AIF-5574968e-856d-40d2-af67-c89a14e76412",
"engines": { "engines": {
"vscode": "^1.25.0" "vscode": "0.10.x"
}, },
"activationEvents": [ "activationEvents": [
"*" "*"
@@ -46,13 +46,7 @@
}, },
"devDependencies": { "devDependencies": {
"mocha-junit-reporter": "^1.17.0", "mocha-junit-reporter": "^1.17.0",
"mocha-multi-reporters": "^1.1.7", "mocha-multi-reporters": "^1.1.7"
"@types/mocha": "^5.2.5",
"@types/node": "^8.10.25",
"mocha": "^5.2.0",
"should": "^13.2.1",
"typemoq": "^2.1.0",
"vscode": "1.1.5"
}, },
"__metadata": { "__metadata": {
"id": "10", "id": "10",

View File

@@ -1,8 +1,3 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict'; 'use strict';
import * as azdata from 'azdata'; import * as azdata from 'azdata';

View File

@@ -3,6 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as data from 'azdata'; import * as data from 'azdata';
@@ -11,6 +12,7 @@ import * as data from 'azdata';
* this API from our code * this API from our code
* *
* @export * @export
* @class ApiWrapper
*/ */
export class ApiWrapper { export class ApiWrapper {
// Data APIs // Data APIs

View File

@@ -50,7 +50,7 @@ export class AlertData implements IAgentDialogData {
private jobModel: JobData; private jobModel: JobData;
constructor( constructor(
ownerUri: string, ownerUri:string,
alertInfo: azdata.AgentAlertInfo, alertInfo: azdata.AgentAlertInfo,
jobModel?: JobData, jobModel?: JobData,
viaJobDialog: boolean = false viaJobDialog: boolean = false

View File

@@ -142,7 +142,7 @@ export class JobData implements IAgentDialogData {
localize('jobData.saveSucessMessage', "Job '{0}' updated successfully", jobInfo.name)); localize('jobData.saveSucessMessage', "Job '{0}' updated successfully", jobInfo.name));
} else { } else {
vscode.window.showInformationMessage( vscode.window.showInformationMessage(
localize('jobData.newJobSuccessMessage', "Job '{0}' created successfully", jobInfo.name)); localize('jobData.newJobSuccessMessage',"Job '{0}' created successfully", jobInfo.name));
} }
} }

View File

@@ -48,7 +48,7 @@ export class JobStepData implements IAgentDialogData {
private jobModel: JobData; private jobModel: JobData;
private viaJobDialog: boolean; private viaJobDialog: boolean;
constructor(ownerUri: string, jobModel?: JobData, viaJobDialog: boolean = false) { constructor(ownerUri:string, jobModel?: JobData, viaJobDialog: boolean = false) {
this.ownerUri = ownerUri; this.ownerUri = ownerUri;
this.jobName = jobModel.name; this.jobName = jobModel.name;
this.jobModel = jobModel; this.jobModel = jobModel;

View File

@@ -29,7 +29,7 @@ export class OperatorData implements IAgentDialogData {
weekdayPagerStartTime: string; weekdayPagerStartTime: string;
weekdayPagerEndTime: string; weekdayPagerEndTime: string;
constructor(ownerUri: string, operatorInfo: azdata.AgentOperatorInfo) { constructor(ownerUri:string, operatorInfo: azdata.AgentOperatorInfo) {
this.ownerUri = ownerUri; this.ownerUri = ownerUri;
if (operatorInfo) { if (operatorInfo) {
this.dialogMode = AgentDialogMode.EDIT; this.dialogMode = AgentDialogMode.EDIT;

View File

@@ -15,7 +15,7 @@ export class PickScheduleData implements IAgentDialogData {
public selectedSchedule: azdata.AgentJobScheduleInfo; public selectedSchedule: azdata.AgentJobScheduleInfo;
private jobName: string; private jobName: string;
constructor(ownerUri: string, jobName: string) { constructor(ownerUri:string, jobName: string) {
this.ownerUri = ownerUri; this.ownerUri = ownerUri;
this.jobName = jobName; this.jobName = jobName;
} }

View File

@@ -22,7 +22,7 @@ export class ProxyData implements IAgentDialogData {
credentialId: number; credentialId: number;
isEnabled: boolean; isEnabled: boolean;
constructor(ownerUri: string, proxyInfo: azdata.AgentProxyInfo) { constructor(ownerUri:string, proxyInfo: azdata.AgentProxyInfo) {
this.ownerUri = ownerUri; this.ownerUri = ownerUri;
if (proxyInfo) { if (proxyInfo) {
@@ -48,7 +48,7 @@ export class ProxyData implements IAgentDialogData {
localize('proxyData.saveSucessMessage', "Proxy '{0}' updated successfully", proxyInfo.accountName)); localize('proxyData.saveSucessMessage', "Proxy '{0}' updated successfully", proxyInfo.accountName));
} else { } else {
vscode.window.showInformationMessage( vscode.window.showInformationMessage(
localize('proxyData.newJobSuccessMessage', "Proxy '{0}' created successfully", proxyInfo.accountName)); localize('proxyData.newJobSuccessMessage',"Proxy '{0}' created successfully", proxyInfo.accountName));
} }
} }

View File

@@ -14,7 +14,7 @@ export class ScheduleData implements IAgentDialogData {
public schedules: azdata.AgentJobScheduleInfo[]; public schedules: azdata.AgentJobScheduleInfo[];
public selectedSchedule: azdata.AgentJobScheduleInfo; public selectedSchedule: azdata.AgentJobScheduleInfo;
constructor(ownerUri: string) { constructor(ownerUri:string) {
this.ownerUri = ownerUri; this.ownerUri = ownerUri;
} }

View File

@@ -332,7 +332,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
if (this.model.severity > 0) { if (this.model.severity > 0) {
this.severityRadioButton.checked = true; this.severityRadioButton.checked = true;
this.severityDropDown.value = this.severityDropDown.values[this.model.severity - 1]; this.severityDropDown.value = this.severityDropDown.values[this.model.severity-1];
} }
if (this.model.databaseName) { if (this.model.databaseName) {
@@ -382,7 +382,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
}, { }, {
component: this.newJobButton, component: this.newJobButton,
title: AlertDialog.NewJobButtonLabel title: AlertDialog.NewJobButtonLabel
}], { componentWidth: '100%' }).component(); }], { componentWidth: '100%'}).component();
let previewTag = view.modelBuilder.text() let previewTag = view.modelBuilder.text()
.withProperties({ .withProperties({
@@ -438,7 +438,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
}, { }, {
component: this.newOperatorButton, component: this.newOperatorButton,
title: '' title: ''
}], { componentWidth: '100%' }).component(); }], { componentWidth: '100%'}).component();
let formModel = view.modelBuilder.formContainer() let formModel = view.modelBuilder.formContainer()
.withFormItems([{ .withFormItems([{

View File

@@ -259,9 +259,9 @@ export class JobDialog extends AgentDialog<JobData> {
width: 140 width: 140
}).component(); }).component();
this.newStepButton.onDidClick((e) => { this.newStepButton.onDidClick((e)=>{
if (this.nameTextBox.value && this.nameTextBox.value.length > 0) { if (this.nameTextBox.value && this.nameTextBox.value.length > 0) {
let stepDialog = new JobStepDialog(this.model.ownerUri, '', this.model, null, true); let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, null, true);
stepDialog.onSuccess((step) => { stepDialog.onSuccess((step) => {
let stepInfo = JobStepData.convertToAgentJobStepInfo(step); let stepInfo = JobStepData.convertToAgentJobStepInfo(step);
this.steps.push(stepInfo); this.steps.push(stepInfo);
@@ -329,7 +329,7 @@ export class JobDialog extends AgentDialog<JobData> {
if (this.stepsTable.selectedRows.length === 1) { if (this.stepsTable.selectedRows.length === 1) {
let rowNumber = this.stepsTable.selectedRows[0]; let rowNumber = this.stepsTable.selectedRows[0];
let stepData = this.model.jobSteps[rowNumber]; let stepData = this.model.jobSteps[rowNumber];
let editStepDialog = new JobStepDialog(this.model.ownerUri, '', this.model, stepData, true); let editStepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, stepData, true);
editStepDialog.onSuccess((step) => { editStepDialog.onSuccess((step) => {
let stepInfo = JobStepData.convertToAgentJobStepInfo(step); let stepInfo = JobStepData.convertToAgentJobStepInfo(step);
for (let i = 0; i < this.steps.length; i++) { for (let i = 0; i < this.steps.length; i++) {
@@ -349,7 +349,7 @@ export class JobDialog extends AgentDialog<JobData> {
} }
}); });
this.deleteStepButton.onDidClick(async () => { this.deleteStepButton.onDidClick(async() => {
if (this.stepsTable.selectedRows.length === 1) { if (this.stepsTable.selectedRows.length === 1) {
let rowNumber = this.stepsTable.selectedRows[0]; let rowNumber = this.stepsTable.selectedRows[0];
AgentUtils.getAgentService().then(async (agentService) => { AgentUtils.getAgentService().then(async (agentService) => {
@@ -448,7 +448,7 @@ export class JobDialog extends AgentDialog<JobData> {
this.alerts.push(alertInfo); this.alerts.push(alertInfo);
this.alertsTable.data = this.convertAlertsToData(this.alerts); this.alertsTable.data = this.convertAlertsToData(this.alerts);
}); });
this.newAlertButton.onDidClick(() => { this.newAlertButton.onDidClick(()=>{
if (this.nameTextBox.value && this.nameTextBox.value.length > 0) { if (this.nameTextBox.value && this.nameTextBox.value.length > 0) {
alertDialog.jobId = this.model.jobId; alertDialog.jobId = this.model.jobId;
alertDialog.jobName = this.model.name ? this.model.name : this.nameTextBox.value; alertDialog.jobName = this.model.name ? this.model.name : this.nameTextBox.value;
@@ -491,7 +491,7 @@ export class JobDialog extends AgentDialog<JobData> {
label: 'Remove schedule', label: 'Remove schedule',
width: 100 width: 100
}).component(); }).component();
this.pickScheduleButton.onDidClick(() => { this.pickScheduleButton.onDidClick(()=>{
let pickScheduleDialog = new PickScheduleDialog(this.model.ownerUri, this.model.name); let pickScheduleDialog = new PickScheduleDialog(this.model.ownerUri, this.model.name);
pickScheduleDialog.onSuccess((dialogModel) => { pickScheduleDialog.onSuccess((dialogModel) => {
let selectedSchedule = dialogModel.selectedSchedule; let selectedSchedule = dialogModel.selectedSchedule;
@@ -610,8 +610,7 @@ export class JobDialog extends AgentDialog<JobData> {
{ {
component: deleteJobContainer, component: deleteJobContainer,
title: '' title: ''
}], title: this.NotificationsTabTopLabelString }], title: this.NotificationsTabTopLabelString}]).withLayout({ width: '100%' }).component();
}]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel); await view.initializeModel(formModel);
this.emailConditionDropdown.values = this.model.JobCompletionActionConditions; this.emailConditionDropdown.values = this.model.JobCompletionActionConditions;

View File

@@ -28,7 +28,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
private readonly GeneralTabText: string = localize('jobStepDialog.general', 'General'); private readonly GeneralTabText: string = localize('jobStepDialog.general', 'General');
private readonly AdvancedTabText: string = localize('jobStepDialog.advanced', 'Advanced'); private readonly AdvancedTabText: string = localize('jobStepDialog.advanced', 'Advanced');
private readonly OpenCommandText: string = localize('jobStepDialog.open', 'Open...'); private readonly OpenCommandText: string = localize('jobStepDialog.open', 'Open...');
private readonly ParseCommandText: string = localize('jobStepDialog.parse', 'Parse'); private readonly ParseCommandText: string = localize('jobStepDialog.parse','Parse');
private readonly SuccessfulParseText: string = localize('jobStepDialog.successParse', 'The command was successfully parsed.'); private readonly SuccessfulParseText: string = localize('jobStepDialog.successParse', 'The command was successfully parsed.');
private readonly FailureParseText: string = localize('jobStepDialog.failParse', 'The command failed.'); private readonly FailureParseText: string = localize('jobStepDialog.failParse', 'The command failed.');
private readonly BlankStepNameErrorText: string = localize('jobStepDialog.blankStepName', 'The step name cannot be left blank'); private readonly BlankStepNameErrorText: string = localize('jobStepDialog.blankStepName', 'The step name cannot be left blank');
@@ -164,7 +164,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
if (this.commandTextBox.value) { if (this.commandTextBox.value) {
queryProvider.parseSyntax(this.ownerUri, this.commandTextBox.value).then(result => { queryProvider.parseSyntax(this.ownerUri, this.commandTextBox.value).then(result => {
if (result && result.parseable) { if (result && result.parseable) {
this.dialog.message = { text: this.SuccessfulParseText, level: 2 }; this.dialog.message = { text: this.SuccessfulParseText, level: 2};
} else if (result && !result.parseable) { } else if (result && !result.parseable) {
this.dialog.message = { text: this.FailureParseText }; this.dialog.message = { text: this.FailureParseText };
} }
@@ -246,7 +246,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
}).component(); }).component();
this.typeDropdown.onValueChanged((type) => { this.typeDropdown.onValueChanged((type) => {
switch (type.selected) { switch (type.selected) {
case (this.TSQLScript): case(this.TSQLScript):
this.runAsDropdown.value = ''; this.runAsDropdown.value = '';
this.runAsDropdown.values = ['']; this.runAsDropdown.values = [''];
this.runAsDropdown.enabled = false; this.runAsDropdown.enabled = false;
@@ -256,7 +256,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
this.processExitCodeBox.value = ''; this.processExitCodeBox.value = '';
this.processExitCodeBox.enabled = false; this.processExitCodeBox.enabled = false;
break; break;
case (this.Powershell): case(this.Powershell):
this.runAsDropdown.value = this.AgentServiceAccount; this.runAsDropdown.value = this.AgentServiceAccount;
this.runAsDropdown.values = [this.runAsDropdown.value]; this.runAsDropdown.values = [this.runAsDropdown.value];
this.runAsDropdown.enabled = true; this.runAsDropdown.enabled = true;
@@ -266,7 +266,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
this.processExitCodeBox.value = ''; this.processExitCodeBox.value = '';
this.processExitCodeBox.enabled = false; this.processExitCodeBox.enabled = false;
break; break;
case (this.CmdExec): case(this.CmdExec):
this.databaseDropdown.enabled = false; this.databaseDropdown.enabled = false;
this.databaseDropdown.values = ['']; this.databaseDropdown.values = [''];
this.databaseDropdown.value = ''; this.databaseDropdown.value = '';
@@ -433,7 +433,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
.withProperties({ ownerUri: this.ownerUri, width: 420, height: 700 }) .withProperties({ ownerUri: this.ownerUri, width: 420, height: 700 })
.component(); .component();
this.selectedPathTextBox = view.modelBuilder.inputBox() this.selectedPathTextBox = view.modelBuilder.inputBox()
.withProperties({ inputType: 'text' }) .withProperties({ inputType: 'text'})
.component(); .component();
this.fileBrowserTree.onDidChange((args) => { this.fileBrowserTree.onDidChange((args) => {
this.selectedPathTextBox.value = args.fullPath; this.selectedPathTextBox.value = args.fullPath;

View File

@@ -135,7 +135,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
this.pagerTuesdayCheckBox.onChanged(() => { this.pagerTuesdayCheckBox.onChanged(() => {
if (this.pagerTuesdayCheckBox.checked) { if (this.pagerTuesdayCheckBox .checked) {
this.weekdayPagerStartTimeInput.enabled = true; this.weekdayPagerStartTimeInput.enabled = true;
this.weekdayPagerEndTimeInput.enabled = true; this.weekdayPagerEndTimeInput.enabled = true;
} else { } else {
@@ -153,7 +153,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
}).component(); }).component();
this.pagerWednesdayCheckBox.onChanged(() => { this.pagerWednesdayCheckBox.onChanged(() => {
if (this.pagerWednesdayCheckBox.checked) { if (this.pagerWednesdayCheckBox .checked) {
this.weekdayPagerStartTimeInput.enabled = true; this.weekdayPagerStartTimeInput.enabled = true;
this.weekdayPagerEndTimeInput.enabled = true; this.weekdayPagerEndTimeInput.enabled = true;
} else { } else {
@@ -171,7 +171,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
}).component(); }).component();
this.pagerThursdayCheckBox.onChanged(() => { this.pagerThursdayCheckBox.onChanged(() => {
if (this.pagerThursdayCheckBox.checked) { if (this.pagerThursdayCheckBox .checked) {
this.weekdayPagerStartTimeInput.enabled = true; this.weekdayPagerStartTimeInput.enabled = true;
this.weekdayPagerEndTimeInput.enabled = true; this.weekdayPagerEndTimeInput.enabled = true;
} else { } else {
@@ -362,7 +362,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
}, { }, {
component: pagerSundayCheckboxContainer, component: pagerSundayCheckboxContainer,
title: '' title: ''
}], }] ,
title: OperatorDialog.PagerDutyScheduleLabel title: OperatorDialog.PagerDutyScheduleLabel
}]).withLayout({ width: '100%' }).component(); }]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel); await view.initializeModel(formModel);

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict'; 'use strict';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
@@ -20,8 +20,8 @@ export class PickScheduleDialog {
private readonly CancelButtonText: string = localize('pickSchedule.cancel', 'Cancel'); private readonly CancelButtonText: string = localize('pickSchedule.cancel', 'Cancel');
private readonly SchedulesLabelText: string = localize('pickSchedule.availableSchedules', 'Available Schedules:'); private readonly SchedulesLabelText: string = localize('pickSchedule.availableSchedules', 'Available Schedules:');
public static readonly ScheduleNameLabelText: string = localize('pickSchedule.scheduleName', 'Name'); public static readonly ScheduleNameLabelText: string = localize('pickSchedule.scheduleName', 'Name');
public static readonly SchedulesIDText: string = localize('pickSchedule.scheduleID', 'ID'); public static readonly SchedulesIDText: string = localize('pickSchedule.scheduleID','ID');
public static readonly ScheduleDescription: string = localize('pickSchedule.description', 'Description'); public static readonly ScheduleDescription: string = localize('pickSchedule.description','Description');
// UI Components // UI Components
@@ -74,7 +74,7 @@ export class PickScheduleDialog {
let data: any[][] = []; let data: any[][] = [];
for (let i = 0; i < this.model.schedules.length; ++i) { for (let i = 0; i < this.model.schedules.length; ++i) {
let schedule = this.model.schedules[i]; let schedule = this.model.schedules[i];
data[i] = [schedule.id, schedule.name, schedule.description]; data[i] = [ schedule.id, schedule.name, schedule.description ];
} }
this.schedulesTable.data = data; this.schedulesTable.data = data;
} }

View File

@@ -84,7 +84,7 @@ export class ProxyDialog extends AgentDialog<ProxyData> {
this.generalTab.registerContent(async view => { this.generalTab.registerContent(async view => {
this.proxyNameTextBox = view.modelBuilder.inputBox() this.proxyNameTextBox = view.modelBuilder.inputBox()
.withProperties({ width: 420 }) .withProperties({width: 420})
.component(); .component();
this.credentialNameDropDown = view.modelBuilder.dropDown() this.credentialNameDropDown = view.modelBuilder.dropDown()

View File

@@ -69,7 +69,7 @@ export class ScheduleDialog {
let data: any[][] = []; let data: any[][] = [];
for (let i = 0; i < this.model.schedules.length; ++i) { for (let i = 0; i < this.model.schedules.length; ++i) {
let schedule = this.model.schedules[i]; let schedule = this.model.schedules[i];
data[i] = [schedule.name]; data[i] = [ schedule.name ];
} }
this.schedulesTable.data = data; this.schedulesTable.data = data;
} }

View File

@@ -43,7 +43,7 @@ export class MainController {
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog(); dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
}); });
vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, server: string, jobInfo: azdata.AgentJobInfo, jobStepInfo: azdata.AgentJobStepInfo) => { vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, server: string, jobInfo: azdata.AgentJobInfo, jobStepInfo: azdata.AgentJobStepInfo) => {
AgentUtils.getAgentService().then(async (agentService) => { AgentUtils.getAgentService().then(async(agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService); let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new JobStepDialog(ownerUri, server, jobData, jobStepInfo, false); let dialog = new JobStepDialog(ownerUri, server, jobData, jobStepInfo, false);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog(); dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();

View File

@@ -0,0 +1,21 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import 'mocha';
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import { JobData } from '../data/jobData';
import { TestAgentService } from './testAgentService';
const testOwnerUri = 'agent://testuri';
suite('Agent extension', () => {
test('Create Job Data', async () => {
let testAgentService = new TestAgentService();
let data = new JobData(testOwnerUri, undefined, testAgentService);
data.save();
});
});

View File

@@ -1,82 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should';
import * as TypeMoq from 'typemoq';
import 'mocha';
import * as azdata from 'azdata';
import { JobData } from '../../data/jobData';
const testOwnerUri = 'agent://testuri';
let mockJobData: TypeMoq.IMock<JobData>;
let mockAgentService: TypeMoq.IMock<azdata.AgentServicesProvider>;
describe('Agent extension create job objects', function (): void {
beforeEach(() => {
mockAgentService = TypeMoq.Mock.ofType<azdata.AgentServicesProvider>();
mockAgentService.setup(s => s.createJob(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => TypeMoq.It.isAny());
mockAgentService.setup(s => s.createJob(undefined, TypeMoq.It.isAny())).returns(() => undefined);
mockAgentService.setup(s => s.createAlert(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => TypeMoq.It.isAny());
mockAgentService.setup(s => s.createAlert(undefined, TypeMoq.It.isAny())).returns(() => undefined);
mockAgentService.setup(s => s.createJobSchedule(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => TypeMoq.It.isAny());
mockAgentService.setup(s => s.createJobSchedule(undefined, TypeMoq.It.isAny())).returns(() => undefined);
mockAgentService.setup(s => s.createJobStep(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => TypeMoq.It.isAny());
mockAgentService.setup(s => s.createJobStep(undefined, TypeMoq.It.isAny())).returns(() => undefined);
mockAgentService.setup(s => s.createOperator(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => TypeMoq.It.isAny());
mockAgentService.setup(s => s.createOperator(undefined, TypeMoq.It.isAny())).returns(() => undefined);
mockAgentService.setup(s => s.createProxy(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => TypeMoq.It.isAny());
mockAgentService.setup(s => s.createProxy(undefined, TypeMoq.It.isAny())).returns(() => undefined);
});
it('Create Job Data', async () => {
// should fail when ownerUri is null
let createJobResult = mockAgentService.object.createJob(null, TypeMoq.It.isAny());
should.strictEqual(createJobResult, undefined);
createJobResult = mockAgentService.object.createJob(testOwnerUri, TypeMoq.It.isAny());
should.notEqual(createJobResult, undefined);
mockJobData = TypeMoq.Mock.ofType<JobData>(JobData, TypeMoq.MockBehavior.Loose, false, [TypeMoq.It.isAnyString(), undefined, mockAgentService]);
});
it('Create Alert Data', async () => {
// should fail when ownerUri is null
let createAlertResult = mockAgentService.object.createAlert(null, TypeMoq.It.isAny());
should.strictEqual(createAlertResult, undefined);
createAlertResult = mockAgentService.object.createAlert(testOwnerUri, TypeMoq.It.isAny());
should.notEqual(createAlertResult, undefined);
});
it('Create Job Schedule Data', async () => {
// should fail when ownerUri is null
let createJobScheduleResult = mockAgentService.object.createJobSchedule(null, TypeMoq.It.isAny());
should.strictEqual(createJobScheduleResult, undefined);
createJobScheduleResult = mockAgentService.object.createJobSchedule(testOwnerUri, TypeMoq.It.isAny());
should.notEqual(createJobScheduleResult, undefined);
});
it('Create Job Step Data', async () => {
// should fail when ownerUri is null
let createJobStepResult = mockAgentService.object.createJobStep(null, TypeMoq.It.isAny());
should.strictEqual(createJobStepResult, undefined);
createJobStepResult = mockAgentService.object.createJobStep(testOwnerUri, TypeMoq.It.isAny());
should.notEqual(createJobStepResult, undefined);
});
it('Create Operator Data', async () => {
// should fail when ownerUri is null
let createOperatorResult = mockAgentService.object.createOperator(null, TypeMoq.It.isAny());
should.strictEqual(createOperatorResult, undefined);
createOperatorResult = mockAgentService.object.createOperator(testOwnerUri, TypeMoq.It.isAny());
should.notEqual(createOperatorResult, undefined);
});
it('Create Proxy Data', async () => {
// should fail when ownerUri is null
let createProxyResult = mockAgentService.object.createProxy(null, TypeMoq.It.isAny());
should.strictEqual(createProxyResult, undefined);
createProxyResult = mockAgentService.object.createProxy(testOwnerUri, TypeMoq.It.isAny());
should.notEqual(createProxyResult, undefined);
});
});

View File

@@ -1,30 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const path = require('path');
const testRunner = require('vscode/lib/testrunner');
const suite = 'Agent Tests';
const options: any = {
ui: 'bdd',
useColors: true,
timeout: 600000
};
if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) {
options.reporter = 'mocha-multi-reporters';
options.reporterOptions = {
reporterEnabled: 'spec, mocha-junit-reporter',
mochaJunitReporterReporterOptions: {
testsuitesTitle: `${suite} ${process.platform}`,
mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`)
}
};
}
testRunner.configure(options);
export = testRunner;

View File

@@ -0,0 +1,110 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
export class TestAgentService implements azdata.AgentServicesProvider {
handle?: number;
readonly providerId: string = 'Test Provider';
// Job management methods
getJobs(ownerUri: string): Thenable<azdata.AgentJobsResult> {
return undefined;
}
getJobHistory(ownerUri: string, jobId: string, jobName: string): Thenable<azdata.AgentJobHistoryResult> {
return undefined;
}
jobAction(ownerUri: string, jobName: string, action: string): Thenable<azdata.ResultStatus> {
return undefined;
}
createJob(ownerUri: string, jobInfo: azdata.AgentJobInfo): Thenable<azdata.CreateAgentJobResult> {
return undefined;
}
updateJob(ownerUri: string, originalJobName: string, jobInfo: azdata.AgentJobInfo): Thenable<azdata.UpdateAgentJobResult> {
return undefined;
}
deleteJob(ownerUri: string, jobInfo: azdata.AgentJobInfo): Thenable<azdata.ResultStatus> {
return undefined;
}
getJobDefaults(ownerUri: string): Thenable<azdata.AgentJobDefaultsResult> {
return undefined;
}
// Job Step management methods
createJobStep(ownerUri: string, jobInfo: azdata.AgentJobStepInfo): Thenable<azdata.CreateAgentJobStepResult> {
return undefined;
}
updateJobStep(ownerUri: string, originalJobStepName: string, jobInfo: azdata.AgentJobStepInfo): Thenable<azdata.UpdateAgentJobStepResult> {
return undefined;
}
deleteJobStep(ownerUri: string, jobInfo: azdata.AgentJobStepInfo): Thenable<azdata.ResultStatus> {
return undefined;
}
// Alert management methods
getAlerts(ownerUri: string): Thenable<azdata.AgentAlertsResult> {
return undefined;
}
createAlert(ownerUri: string, alertInfo: azdata.AgentAlertInfo): Thenable<azdata.CreateAgentAlertResult> {
return undefined;
}
updateAlert(ownerUri: string, originalAlertName: string, alertInfo: azdata.AgentAlertInfo): Thenable<azdata.UpdateAgentAlertResult> {
return undefined;
}
deleteAlert(ownerUri: string, alertInfo: azdata.AgentAlertInfo): Thenable<azdata.ResultStatus> {
return undefined;
}
// Operator management methods
getOperators(ownerUri: string): Thenable<azdata.AgentOperatorsResult> {
return undefined;
}
createOperator(ownerUri: string, operatorInfo: azdata.AgentOperatorInfo): Thenable<azdata.CreateAgentOperatorResult> {
return undefined;
}
updateOperator(ownerUri: string, originalOperatorName: string, operatorInfo: azdata.AgentOperatorInfo): Thenable<azdata.UpdateAgentOperatorResult> {
return undefined;
}
deleteOperator(ownerUri: string, operatorInfo: azdata.AgentOperatorInfo): Thenable<azdata.ResultStatus> {
return undefined;
}
// Proxy management methods
getProxies(ownerUri: string): Thenable<azdata.AgentProxiesResult> {
return undefined;
}
createProxy(ownerUri: string, proxyInfo: azdata.AgentProxyInfo): Thenable<azdata.CreateAgentOperatorResult> {
return undefined;
}
updateProxy(ownerUri: string, originalProxyName: string, proxyInfo: azdata.AgentProxyInfo): Thenable<azdata.UpdateAgentOperatorResult> {
return undefined;
}
deleteProxy(ownerUri: string, proxyInfo: azdata.AgentProxyInfo): Thenable<azdata.ResultStatus> {
return undefined;
}
// Agent Credential method
getCredentials(ownerUri: string): Thenable<azdata.GetCredentialsResult> {
return undefined;
}
// Job Schedule management methods
getJobSchedules(ownerUri: string): Thenable<azdata.AgentJobSchedulesResult> {
return undefined;
}
createJobSchedule(ownerUri: string, scheduleInfo: azdata.AgentJobScheduleInfo): Thenable<azdata.CreateAgentJobScheduleResult> {
return undefined;
}
updateJobSchedule(ownerUri: string, originalScheduleName: string, scheduleInfo: azdata.AgentJobScheduleInfo): Thenable<azdata.UpdateAgentJobScheduleResult> {
return undefined;
}
deleteJobSchedule(ownerUri: string, scheduleInfo: azdata.AgentJobScheduleInfo): Thenable<azdata.ResultStatus> {
return undefined;
}
registerOnUpdated(handler: () => any): void {
}
}

View File

@@ -10,7 +10,8 @@
"sourceMap": true, "sourceMap": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"moduleResolution": "node" "moduleResolution": "node",
"declaration": true
}, },
"exclude": [ "exclude": [
"node_modules" "node_modules"

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +0,0 @@
src/**
out/**
tsconfig.json
extension.webpack.config.js
yarn.lock

View File

@@ -42,15 +42,15 @@
{ {
"id": "microsoft", "id": "microsoft",
"icon": { "icon": {
"light": "./resources/light/microsoft_account_light.svg", "light": "./out/account-provider/media/microsoft_account_light.svg",
"dark": "./resources/dark/microsoft_account_dark.svg" "dark": "./out/account-provider/media/microsoft_account_dark.svg"
} }
}, },
{ {
"id": "work_school", "id": "work_school",
"icon": { "icon": {
"light": "./resources/light/work_school_account_light.svg", "light": "./out/account-provider/media/work_school_account_light.svg",
"dark": "./resources/dark/work_school_account_dark.svg" "dark": "./out/account-provider/media/work_school_account_dark.svg"
} }
} }
], ],
@@ -104,8 +104,8 @@
"command": "azure.resource.connectsqldb", "command": "azure.resource.connectsqldb",
"title": "%azure.resource.connectsqldb.title%", "title": "%azure.resource.connectsqldb.title%",
"icon": { "icon": {
"dark": "resources/dark/add_to_server_list_inverse.svg", "dark": "resources/dark/connect_to_inverse.svg",
"light": "resources/light/add_to_server_list.svg" "light": "resources/light/connect_to.svg"
} }
} }
], ],
@@ -156,19 +156,17 @@
"hasAzureResourceProviders": true "hasAzureResourceProviders": true
}, },
"dependencies": { "dependencies": {
"adal-node": "^0.1.28",
"azure-arm-resource": "^7.0.0", "azure-arm-resource": "^7.0.0",
"azure-arm-sql": "^5.0.1", "azure-arm-sql": "^5.0.1",
"ms-rest": "^2.5.0",
"request": "2.88.0", "request": "2.88.0",
"vscode-nls": "^4.0.0" "vscode-nls": "^4.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/mocha": "^5.2.5", "@types/mocha": "^5.2.5",
"@types/node": "^10.12.12", "@types/node": "^8.0.24",
"@types/request": "^2.48.1",
"mocha": "^5.2.0", "mocha": "^5.2.0",
"should": "^13.2.1", "should": "^13.2.1",
"typemoq": "^2.1.0" "typemoq": "^2.1.0",
"vscode": "^1.1.26"
} }
} }

View File

@@ -10,8 +10,8 @@
"azure.resource.refresh.title": "Refresh", "azure.resource.refresh.title": "Refresh",
"azure.resource.signin.title": "Sign In", "azure.resource.signin.title": "Sign In",
"azure.resource.selectsubscriptions.title": "Select Subscriptions", "azure.resource.selectsubscriptions.title": "Select Subscriptions",
"azure.resource.connectsqlserver.title": "Connect", "azure.resource.connectsqlserver.title": "Add to Servers",
"azure.resource.connectsqldb.title": "Add to Servers", "azure.resource.connectsqldb.title": "Connect",
"accounts.clearTokenCache": "Clear Azure Account Token Cache", "accounts.clearTokenCache": "Clear Azure Account Token Cache",

View File

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 12H16V13H13V16H12V13H9V12H12V9H13V12ZM1 6V5H2V6H1ZM15 5V6H4V5H15ZM1 3V2H2V3H1ZM15 2V3H4V2H15Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 226 B

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16"><defs><style>.cls-1,.cls-2{clip-rule:evenodd;}.cls-2,.cls-5,.cls-7{fill:#fff;}.cls-3,.cls-5{fill-rule:evenodd;}.cls-4{clip-path:url(#clip-path);}.cls-6{clip-path:url(#clip-path-2);}</style><clipPath id="clip-path"><path class="cls-1" d="M11.5-15.92v3.5a3.4,3.4,0,0,1-.23,1.24,3.48,3.48,0,0,1-.63,1.05,3.57,3.57,0,0,1-1,.77A3.43,3.43,0,0,1,8.5-9v6h-1V-9a3.39,3.39,0,0,1-1.2-.4,3.59,3.59,0,0,1-.95-.77,3.48,3.48,0,0,1-.63-1.05,3.4,3.4,0,0,1-.23-1.24v-3.5h1v-3h1v3h3v-3h1v3Zm-1,1h-5v2.5a2.45,2.45,0,0,0,.2,1,2.53,2.53,0,0,0,.53.8,2.53,2.53,0,0,0,.8.53,2.45,2.45,0,0,0,1,.2,2.42,2.42,0,0,0,1-.2,2.53,2.53,0,0,0,.79-.53,2.59,2.59,0,0,0,.54-.8,2.41,2.41,0,0,0,.2-1Z"/></clipPath><clipPath id="clip-path-2"><path class="cls-2" d="M11.5,3V6.5a3.4,3.4,0,0,1-.23,1.24,3.48,3.48,0,0,1-.63,1.05,3.57,3.57,0,0,1-1,.77A3.43,3.43,0,0,1,8.5,10v6h-1V10a3.39,3.39,0,0,1-1.2-.4,3.59,3.59,0,0,1-.95-.77,3.48,3.48,0,0,1-.63-1.05A3.4,3.4,0,0,1,4.5,6.5V3h1V0h1V3h3V0h1V3Zm-1,1h-5V6.5a2.45,2.45,0,0,0,.2,1A2.49,2.49,0,0,0,7,8.8,2.45,2.45,0,0,0,8,9a2.42,2.42,0,0,0,1-.2,2.53,2.53,0,0,0,.79-.53,2.59,2.59,0,0,0,.54-.8,2.41,2.41,0,0,0,.2-1Z"/></clipPath></defs><title>connect_to_inverse</title><path class="cls-3" d="M11.5-15.92v3.5a3.4,3.4,0,0,1-.23,1.24,3.48,3.48,0,0,1-.63,1.05,3.57,3.57,0,0,1-1,.77A3.43,3.43,0,0,1,8.5-9v6h-1V-9a3.39,3.39,0,0,1-1.2-.4,3.59,3.59,0,0,1-.95-.77,3.48,3.48,0,0,1-.63-1.05,3.4,3.4,0,0,1-.23-1.24v-3.5h1v-3h1v3h3v-3h1v3Zm-1,1h-5v2.5a2.45,2.45,0,0,0,.2,1,2.53,2.53,0,0,0,.53.8,2.53,2.53,0,0,0,.8.53,2.45,2.45,0,0,0,1,.2,2.42,2.42,0,0,0,1-.2,2.53,2.53,0,0,0,.79-.53,2.59,2.59,0,0,0,.54-.8,2.41,2.41,0,0,0,.2-1Z"/><g class="cls-4"><rect x="-0.5" y="-23.92" width="17" height="26"/></g><path class="cls-5" d="M11.5,3V6.5a3.4,3.4,0,0,1-.23,1.24,3.48,3.48,0,0,1-.63,1.05,3.57,3.57,0,0,1-1,.77A3.43,3.43,0,0,1,8.5,10v6h-1V10a3.39,3.39,0,0,1-1.2-.4,3.59,3.59,0,0,1-.95-.77,3.48,3.48,0,0,1-.63-1.05A3.4,3.4,0,0,1,4.5,6.5V3h1V0h1V3h3V0h1V3Zm-1,1h-5V6.5a2.45,2.45,0,0,0,.2,1A2.49,2.49,0,0,0,7,8.8,2.45,2.45,0,0,0,8,9a2.42,2.42,0,0,0,1-.2,2.53,2.53,0,0,0,.79-.53,2.59,2.59,0,0,0,.54-.8,2.41,2.41,0,0,0,.2-1Z"/><g class="cls-6"><rect class="cls-7" x="-0.5" y="-5" width="17" height="26"/></g></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 12H16V13H13V16H12V13H9V12H12V9H13V12ZM1 6V5H2V6H1ZM15 5V6H4V5H15ZM1 3V2H2V3H1ZM15 2V3H4V2H15Z" fill="#333333"/>
</svg>

Before

Width:  |  Height:  |  Size: 228 B

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16"><defs><style>.cls-1,.cls-2{clip-rule:evenodd;}.cls-2,.cls-5,.cls-7{fill:#fff;}.cls-3,.cls-5{fill-rule:evenodd;}.cls-4{clip-path:url(#clip-path);}.cls-6{clip-path:url(#clip-path-2);}</style><clipPath id="clip-path"><path class="cls-1" d="M11.5,3V6.5a3.4,3.4,0,0,1-.23,1.24,3.48,3.48,0,0,1-.63,1.05,3.57,3.57,0,0,1-1,.77A3.43,3.43,0,0,1,8.5,10v6h-1V10a3.39,3.39,0,0,1-1.2-.4,3.59,3.59,0,0,1-.95-.77,3.48,3.48,0,0,1-.63-1.05A3.4,3.4,0,0,1,4.5,6.5V3h1V0h1V3h3V0h1V3Zm-1,1h-5V6.5a2.45,2.45,0,0,0,.2,1A2.49,2.49,0,0,0,7,8.8,2.45,2.45,0,0,0,8,9a2.42,2.42,0,0,0,1-.2,2.53,2.53,0,0,0,.79-.53,2.59,2.59,0,0,0,.54-.8,2.41,2.41,0,0,0,.2-1Z"/></clipPath><clipPath id="clip-path-2"><path class="cls-2" d="M11.5,21.92v3.5a3.4,3.4,0,0,1-.23,1.24,3.48,3.48,0,0,1-.63,1.05,3.57,3.57,0,0,1-1,.77,3.43,3.43,0,0,1-1.19.4v6h-1v-6a3.39,3.39,0,0,1-1.2-.4,3.59,3.59,0,0,1-.95-.77,3.48,3.48,0,0,1-.63-1.05,3.4,3.4,0,0,1-.23-1.24v-3.5h1v-3h1v3h3v-3h1v3Zm-1,1h-5v2.5a2.45,2.45,0,0,0,.2,1A2.49,2.49,0,0,0,7,27.72a2.45,2.45,0,0,0,1,.2,2.42,2.42,0,0,0,1-.2,2.53,2.53,0,0,0,.79-.53,2.59,2.59,0,0,0,.54-.8,2.41,2.41,0,0,0,.2-1Z"/></clipPath></defs><title>connect_to</title><path class="cls-3" d="M11.5,3V6.5a3.4,3.4,0,0,1-.23,1.24,3.48,3.48,0,0,1-.63,1.05,3.57,3.57,0,0,1-1,.77A3.43,3.43,0,0,1,8.5,10v6h-1V10a3.39,3.39,0,0,1-1.2-.4,3.59,3.59,0,0,1-.95-.77,3.48,3.48,0,0,1-.63-1.05A3.4,3.4,0,0,1,4.5,6.5V3h1V0h1V3h3V0h1V3Zm-1,1h-5V6.5a2.45,2.45,0,0,0,.2,1A2.49,2.49,0,0,0,7,8.8,2.45,2.45,0,0,0,8,9a2.42,2.42,0,0,0,1-.2,2.53,2.53,0,0,0,.79-.53,2.59,2.59,0,0,0,.54-.8,2.41,2.41,0,0,0,.2-1Z"/><g class="cls-4"><rect x="-0.5" y="-5" width="17" height="26"/></g><path class="cls-5" d="M11.5,21.92v3.5a3.4,3.4,0,0,1-.23,1.24,3.48,3.48,0,0,1-.63,1.05,3.57,3.57,0,0,1-1,.77,3.43,3.43,0,0,1-1.19.4v6h-1v-6a3.39,3.39,0,0,1-1.2-.4,3.59,3.59,0,0,1-.95-.77,3.48,3.48,0,0,1-.63-1.05,3.4,3.4,0,0,1-.23-1.24v-3.5h1v-3h1v3h3v-3h1v3Zm-1,1h-5v2.5a2.45,2.45,0,0,0,.2,1A2.49,2.49,0,0,0,7,27.72a2.45,2.45,0,0,0,1,.2,2.42,2.42,0,0,0,1-.2,2.53,2.53,0,0,0,.79-.53,2.59,2.59,0,0,0,.54-.8,2.41,2.41,0,0,0,.2-1Z"/><g class="cls-6"><rect class="cls-7" x="-0.5" y="13.92" width="17" height="26"/></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -3,6 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
import * as adal from 'adal-node'; import * as adal from 'adal-node';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as request from 'request'; import * as request from 'request';
@@ -10,6 +12,7 @@ import * as nls from 'vscode-nls';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as url from 'url'; import * as url from 'url';
import { import {
Arguments,
AzureAccount, AzureAccount,
AzureAccountProviderMetadata, AzureAccountProviderMetadata,
AzureAccountSecurityTokenCollection, AzureAccountSecurityTokenCollection,
@@ -26,12 +29,17 @@ export class AzureAccountProvider implements azdata.AccountProvider {
private static AadCommonTenant: string = 'common'; private static AadCommonTenant: string = 'common';
// MEMBER VARIABLES //////////////////////////////////////////////////// // MEMBER VARIABLES ////////////////////////////////////////////////////
private _args: Arguments;
private _autoOAuthCancelled: boolean; private _autoOAuthCancelled: boolean;
private _commonAuthorityUrl: string; private _commonAuthorityUrl: string;
private _inProgressAutoOAuth: InProgressAutoOAuth; private _inProgressAutoOAuth: InProgressAutoOAuth;
private _isInitialized: boolean; private _isInitialized: boolean;
constructor(private _metadata: AzureAccountProviderMetadata, private _tokenCache: TokenCache) { constructor(private _metadata: AzureAccountProviderMetadata, private _tokenCache: TokenCache) {
this._args = {
host: this._metadata.settings.host,
clientId: this._metadata.settings.clientId
};
this._autoOAuthCancelled = false; this._autoOAuthCancelled = false;
this._inProgressAutoOAuth = null; this._inProgressAutoOAuth = null;
this._isInitialized = false; this._isInitialized = false;
@@ -46,8 +54,8 @@ export class AzureAccountProvider implements azdata.AccountProvider {
/** /**
* Clears all tokens that belong to the given account from the token cache * Clears all tokens that belong to the given account from the token cache
* @param accountKey Key identifying the account to delete tokens for * @param {"data".AccountKey} accountKey Key identifying the account to delete tokens for
* @returns Promise to clear requested tokens from the token cache * @returns {Thenable<void>} Promise to clear requested tokens from the token cache
*/ */
public clear(accountKey: azdata.AccountKey): Thenable<void> { public clear(accountKey: azdata.AccountKey): Thenable<void> {
return this.doIfInitialized(() => this.clearAccountTokens(accountKey)); return this.doIfInitialized(() => this.clearAccountTokens(accountKey));
@@ -55,7 +63,7 @@ export class AzureAccountProvider implements azdata.AccountProvider {
/** /**
* Clears the entire token cache. Invoked by command palette action. * Clears the entire token cache. Invoked by command palette action.
* @returns Promise to clear the token cache * @returns {Thenable<void>} Promise to clear the token cache
*/ */
public clearTokenCache(): Thenable<void> { public clearTokenCache(): Thenable<void> {
return this._tokenCache.clear(); return this._tokenCache.clear();
@@ -313,10 +321,10 @@ export class AzureAccountProvider implements azdata.AccountProvider {
* Retrieves a token for the given user ID for the specific tenant ID. If the token can, it * Retrieves a token for the given user ID for the specific tenant ID. If the token can, it
* will be retrieved from the cache as per the ADAL API. AFAIK, the ADAL API will also utilize * will be retrieved from the cache as per the ADAL API. AFAIK, the ADAL API will also utilize
* the refresh token if there aren't any unexpired tokens to use. * the refresh token if there aren't any unexpired tokens to use.
* @param userId ID of the user to get a token for * @param {string} userId ID of the user to get a token for
* @param tenantId Tenant to get the token for * @param {string} tenantId Tenant to get the token for
* @param resourceId ID of the resource the token will be good for * @param {string} resourceId ID of the resource the token will be good for
* @returns Promise to return a token. Rejected if retrieving the token fails. * @returns {Thenable<TokenResponse>} Promise to return a token. Rejected if retrieving the token fails.
*/ */
private getToken(userId: string, tenantId: string, resourceId: string): Thenable<adal.TokenResponse> { private getToken(userId: string, tenantId: string, resourceId: string): Thenable<adal.TokenResponse> {
let self = this; let self = this;
@@ -338,9 +346,9 @@ export class AzureAccountProvider implements azdata.AccountProvider {
/** /**
* Performs a web request using the provided bearer token * Performs a web request using the provided bearer token
* @param accessToken Bearer token for accessing the provided URI * @param {TokenResponse} accessToken Bearer token for accessing the provided URI
* @param uri URI to access * @param {string} uri URI to access
* @returns Promise to return the deserialized body of the request. Rejected if error occurred. * @returns {Thenable<any>} Promise to return the deserialized body of the request. Rejected if error occurred.
*/ */
private makeWebRequest(accessToken: adal.TokenResponse, uri: string): Thenable<any> { private makeWebRequest(accessToken: adal.TokenResponse, uri: string): Thenable<any> {
return new Promise<any>((resolve, reject) => { return new Promise<any>((resolve, reject) => {
@@ -355,7 +363,7 @@ export class AzureAccountProvider implements azdata.AccountProvider {
}; };
// Setup the callback to resolve/reject this promise // Setup the callback to resolve/reject this promise
const callback: request.RequestCallback = (error, response, body: { error: any; value: any; }) => { let callback = (error, response, body: { error: any; value: any; }) => {
if (error || body.error) { if (error || body.error) {
reject(error || JSON.stringify(body.error)); reject(error || JSON.stringify(body.error));
} else { } else {
@@ -425,7 +433,6 @@ export class AzureAccountProvider implements azdata.AccountProvider {
name: tokenResponse.userId, name: tokenResponse.userId,
displayInfo: { displayInfo: {
accountType: accountType, accountType: accountType,
userId: tokenResponse.userId,
contextualDisplayName: contextualDisplayName, contextualDisplayName: contextualDisplayName,
displayName: displayName displayName: displayName
}, },

View File

@@ -1,8 +1,3 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict'; 'use strict';
import * as azdata from 'azdata'; import * as azdata from 'azdata';

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -3,6 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
import * as adal from 'adal-node'; import * as adal from 'adal-node';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as crypto from 'crypto'; import * as crypto from 'crypto';
@@ -77,7 +79,7 @@ export default class TokenCache implements adal.TokenCache {
/** /**
* Wrapper to make callback-based find method into a thenable method * Wrapper to make callback-based find method into a thenable method
* @param query Partial object to use to look up tokens. Ideally should be partial of adal.TokenResponse * @param query Partial object to use to look up tokens. Ideally should be partial of adal.TokenResponse
* @returns Promise to return the matching adal.TokenResponse objects. * @returns {Thenable<any[]>} Promise to return the matching adal.TokenResponse objects.
* Rejected if an error was sent in the callback * Rejected if an error was sent in the callback
*/ */
public findThenable(query: any): Thenable<any[]> { public findThenable(query: any): Thenable<any[]> {
@@ -110,8 +112,8 @@ export default class TokenCache implements adal.TokenCache {
/** /**
* Wrapper to make callback-based remove method into a thenable method * Wrapper to make callback-based remove method into a thenable method
* @param entries Array of entries to remove from the token cache * @param {TokenResponse[]} entries Array of entries to remove from the token cache
* @returns Promise to remove the given tokens from the token cache * @returns {Thenable<void>} Promise to remove the given tokens from the token cache
* Rejected if an error was sent in the callback * Rejected if an error was sent in the callback
*/ */
public removeThenable(entries: adal.TokenResponse[]): Thenable<void> { public removeThenable(entries: adal.TokenResponse[]): Thenable<void> {
@@ -136,7 +138,7 @@ export default class TokenCache implements adal.TokenCache {
&& entry1.resource === entry2.resource; && entry1.resource === entry2.resource;
} }
private static findByPartial(entry: adal.TokenResponse, query: { [key: string]: any }): boolean { private static findByPartial(entry: adal.TokenResponse, query: object): boolean {
for (let key in query) { for (let key in query) {
if (entry[key] === undefined || entry[key] !== query[key]) { if (entry[key] === undefined || entry[key] !== query[key]) {
return false; return false;
@@ -184,8 +186,8 @@ export default class TokenCache implements adal.TokenCache {
if (splitValues.length === 2 && splitValues[0] && splitValues[1]) { if (splitValues.length === 2 && splitValues[0] && splitValues[1]) {
try { try {
return <EncryptionParams>{ return <EncryptionParams>{
key: Buffer.from(splitValues[0], 'hex'), key: new Buffer(splitValues[0], 'hex'),
initializationVector: Buffer.from(splitValues[1], 'hex') initializationVector: new Buffer(splitValues[1], 'hex')
}; };
} catch (e) { } catch (e) {
// Swallow the error and fall through to generate new params // Swallow the error and fall through to generate new params

View File

@@ -3,6 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
@@ -13,6 +15,7 @@ import * as constants from './constants';
* this API from our code * this API from our code
* *
* @export * @export
* @class ApiWrapper
*/ */
export class ApiWrapper { export class ApiWrapper {
// Data APIs // Data APIs
@@ -153,6 +156,12 @@ export class ApiWrapper {
return vscode.window.showSaveDialog(options); return vscode.window.showSaveDialog(options);
} }
public openTextDocument(uri: vscode.Uri): Thenable<vscode.TextDocument>;
public openTextDocument(options: { language?: string; content?: string; }): Thenable<vscode.TextDocument>;
public openTextDocument(uriOrOptions): Thenable<vscode.TextDocument> {
return vscode.workspace.openTextDocument(uriOrOptions);
}
public showTextDocument(document: vscode.TextDocument, column?: vscode.ViewColumn, preserveFocus?: boolean, preview?: boolean): Thenable<vscode.TextEditor> { public showTextDocument(document: vscode.TextDocument, column?: vscode.ViewColumn, preserveFocus?: boolean, preview?: boolean): Thenable<vscode.TextEditor> {
let options: vscode.TextDocumentShowOptions = { let options: vscode.TextDocumentShowOptions = {
viewColumn: column, viewColumn: column,
@@ -203,7 +212,7 @@ export class ApiWrapper {
return azdata.accounts.getAllAccounts(); return azdata.accounts.getAllAccounts();
} }
public getSecurityToken(account: azdata.Account, resource: azdata.AzureResource): Thenable<{ [key: string]: any }> { public getSecurityToken(account: azdata.Account, resource: azdata.AzureResource): Thenable<{}> {
return azdata.accounts.getSecurityToken(account, resource); return azdata.accounts.getSecurityToken(account, resource);
} }

View File

@@ -3,6 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { ApiWrapper } from './apiWrapper'; import { ApiWrapper } from './apiWrapper';

View File

@@ -16,7 +16,8 @@ import { AzureResourceResourceTreeNode } from '../../resourceTreeNode';
export function registerAzureResourceDatabaseCommands(appContext: AppContext): void { export function registerAzureResourceDatabaseCommands(appContext: AppContext): void {
appContext.apiWrapper.registerCommand('azure.resource.connectsqldb', async (node?: TreeNode) => { appContext.apiWrapper.registerCommand('azure.resource.connectsqldb', async (node?: TreeNode) => {
if (!node) { if (!node)
{
return; return;
} }

View File

@@ -16,7 +16,8 @@ import { AzureResourceResourceTreeNode } from '../../resourceTreeNode';
export function registerAzureResourceDatabaseServerCommands(appContext: AppContext): void { export function registerAzureResourceDatabaseServerCommands(appContext: AppContext): void {
appContext.apiWrapper.registerCommand('azure.resource.connectsqlserver', async (node?: TreeNode) => { appContext.apiWrapper.registerCommand('azure.resource.connectsqlserver', async (node?: TreeNode) => {
if (!node) { if (!node)
{
return; return;
} }

View File

@@ -12,7 +12,7 @@ import { azureResource } from '../azure-resource';
import { IAzureResourceSubscriptionFilterService, IAzureResourceCacheService } from '../interfaces'; import { IAzureResourceSubscriptionFilterService, IAzureResourceCacheService } from '../interfaces';
interface AzureResourceSelectedSubscriptionsCache { interface AzureResourceSelectedSubscriptionsCache {
selectedSubscriptions: { [accountId: string]: azureResource.AzureResourceSubscription[] }; selectedSubscriptions: { [accountId: string]: azureResource.AzureResourceSubscription[]};
} }
export class AzureResourceSubscriptionFilterService implements IAzureResourceSubscriptionFilterService { export class AzureResourceSubscriptionFilterService implements IAzureResourceSubscriptionFilterService {
@@ -36,7 +36,7 @@ export class AzureResourceSubscriptionFilterService implements IAzureResourceSub
} }
public async saveSelectedSubscriptions(account: Account, selectedSubscriptions: azureResource.AzureResourceSubscription[]): Promise<void> { public async saveSelectedSubscriptions(account: Account, selectedSubscriptions: azureResource.AzureResourceSubscription[]): Promise<void> {
let selectedSubscriptionsCache: { [accountId: string]: azureResource.AzureResourceSubscription[] } = {}; let selectedSubscriptionsCache: { [accountId: string]: azureResource.AzureResourceSubscription[]} = {};
const cache = this._cacheService.get<AzureResourceSelectedSubscriptionsCache>(this._cacheKey); const cache = this._cacheService.get<AzureResourceSelectedSubscriptionsCache>(this._cacheKey);
if (cache) { if (cache) {

View File

@@ -3,6 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
import { TreeItem, TreeItemCollapsibleState } from 'vscode'; import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { Account, NodeInfo, AzureResource } from 'azdata'; import { Account, NodeInfo, AzureResource } from 'azdata';
import { TokenCredentials } from 'ms-rest'; import { TokenCredentials } from 'ms-rest';

View File

@@ -1,7 +1,4 @@
/*--------------------------------------------------------------------------------------------- 'use strict';
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';

View File

@@ -3,16 +3,17 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
import ControllerBase from './controllerBase'; import ControllerBase from './controllerBase';
import { DidChangeAccountsParams, Account } from 'azdata'; import { DidChangeAccountsParams } from 'azdata';
import { import {
IAzureResourceCacheService, IAzureResourceCacheService,
IAzureResourceAccountService, IAzureResourceAccountService,
IAzureResourceSubscriptionService, IAzureResourceSubscriptionService,
IAzureResourceSubscriptionFilterService, IAzureResourceSubscriptionFilterService,
IAzureResourceTenantService IAzureResourceTenantService } from '../azureResource/interfaces';
} from '../azureResource/interfaces';
import { AzureResourceServiceNames } from '../azureResource/constants'; import { AzureResourceServiceNames } from '../azureResource/constants';
import { AzureResourceTreeProvider } from '../azureResource/tree/treeProvider'; import { AzureResourceTreeProvider } from '../azureResource/tree/treeProvider';
import { registerAzureResourceCommands } from '../azureResource/commands'; import { registerAzureResourceCommands } from '../azureResource/commands';
@@ -37,7 +38,7 @@ export default class AzureResourceController extends ControllerBase {
const azureResourceTree = new AzureResourceTreeProvider(this.appContext); const azureResourceTree = new AzureResourceTreeProvider(this.appContext);
this.extensionContext.subscriptions.push(this.apiWrapper.registerTreeDataProvider('azureResourceExplorer', azureResourceTree)); this.extensionContext.subscriptions.push(this.apiWrapper.registerTreeDataProvider('azureResourceExplorer', azureResourceTree));
let previousAccounts: Array<Account> = undefined; let previousAccounts = undefined;
this.appContext.getService<IAzureResourceAccountService>(AzureResourceServiceNames.accountService).onDidChangeAccounts((e: DidChangeAccountsParams) => { this.appContext.getService<IAzureResourceAccountService>(AzureResourceServiceNames.accountService).onDidChangeAccounts((e: DidChangeAccountsParams) => {
// the onDidChangeAccounts event will trigger in many cases where the accounts didn't actually change // the onDidChangeAccounts event will trigger in many cases where the accounts didn't actually change
// the notifyNodeChanged event triggers a refresh which triggers a getChildren which can trigger this callback // the notifyNodeChanged event triggers a refresh which triggers a getChildren which can trigger this callback

View File

@@ -1,7 +1,4 @@
/*--------------------------------------------------------------------------------------------- 'use strict';
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as fs from 'fs'; import * as fs from 'fs';
@@ -26,7 +23,7 @@ let controllers: ControllerBase[] = [];
// The function is a duplicate of \src\paths.js. IT would be better to import path.js but it doesn't // The function is a duplicate of \src\paths.js. IT would be better to import path.js but it doesn't
// work for now because the extension is running in different process. // work for now because the extension is running in different process.
export function getAppDataPath() { export function getAppDataPath() {
let platform = process.platform; var platform = process.platform;
switch (platform) { switch (platform) {
case 'win32': return process.env['APPDATA'] || path.join(process.env['USERPROFILE'], 'AppData', 'Roaming'); case 'win32': return process.env['APPDATA'] || path.join(process.env['USERPROFILE'], 'AppData', 'Roaming');
case 'darwin': return path.join(os.homedir(), 'Library', 'Application Support'); case 'darwin': return path.join(os.homedir(), 'Library', 'Application Support');
@@ -57,7 +54,7 @@ export function activate(extensionContext: vscode.ExtensionContext) {
} catch (e) { } catch (e) {
console.error(`Initialization of Azure account extension storage failed: ${e}`); console.error(`Initialization of Azure account extension storage failed: ${e}`);
console.error('Azure accounts will not be available'); console.error('Azure accounts will not be available');
return undefined; return;
} }
// Create the provider service and activate // Create the provider service and activate

View File

@@ -3,6 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should'; import * as should from 'should';
import * as TypeMoq from 'typemoq'; import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
@@ -30,8 +32,7 @@ const mockAccount: azdata.Account = {
displayInfo: { displayInfo: {
displayName: 'mock_account@test.com', displayName: 'mock_account@test.com',
accountType: 'Microsoft', accountType: 'Microsoft',
contextualDisplayName: 'test', contextualDisplayName: 'test'
userId: 'test@email.com'
}, },
properties: undefined, properties: undefined,
isStale: false isStale: false
@@ -57,7 +58,7 @@ const mockResourceRootNode: azureResource.IAzureResourceNode = {
} }
}; };
const mockTokens: { [key: string]: any } = {}; const mockTokens = {};
mockTokens[mockTenantId] = { mockTokens[mockTenantId] = {
token: 'mock_token', token: 'mock_token',
tokenType: 'Bearer' tokenType: 'Bearer'
@@ -78,14 +79,14 @@ const mockDatabases: AzureResourceDatabase[] = [
} }
]; ];
describe('AzureResourceDatabaseTreeDataProvider.info', function (): void { describe('AzureResourceDatabaseTreeDataProvider.info', function(): void {
beforeEach(() => { beforeEach(() => {
mockDatabaseService = TypeMoq.Mock.ofType<IAzureResourceDatabaseService>(); mockDatabaseService = TypeMoq.Mock.ofType<IAzureResourceDatabaseService>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>(); mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>(); mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
}); });
it('Should be correct when created.', async function (): Promise<void> { it('Should be correct when created.', async function(): Promise<void> {
const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockApiWrapper.object, mockExtensionContext.object); const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockApiWrapper.object, mockExtensionContext.object);
const treeItem = await treeDataProvider.getTreeItem(mockResourceRootNode); const treeItem = await treeDataProvider.getTreeItem(mockResourceRootNode);
@@ -96,7 +97,7 @@ describe('AzureResourceDatabaseTreeDataProvider.info', function (): void {
}); });
}); });
describe('AzureResourceDatabaseTreeDataProvider.getChildren', function (): void { describe('AzureResourceDatabaseTreeDataProvider.getChildren', function(): void {
beforeEach(() => { beforeEach(() => {
mockDatabaseService = TypeMoq.Mock.ofType<IAzureResourceDatabaseService>(); mockDatabaseService = TypeMoq.Mock.ofType<IAzureResourceDatabaseService>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>(); mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
@@ -107,7 +108,7 @@ describe('AzureResourceDatabaseTreeDataProvider.getChildren', function (): void
mockExtensionContext.setup((o) => o.asAbsolutePath(TypeMoq.It.isAnyString())).returns(() => TypeMoq.It.isAnyString()); mockExtensionContext.setup((o) => o.asAbsolutePath(TypeMoq.It.isAnyString())).returns(() => TypeMoq.It.isAnyString());
}); });
it('Should return container node when element is undefined.', async function (): Promise<void> { it('Should return container node when element is undefined.', async function(): Promise<void> {
const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockApiWrapper.object, mockExtensionContext.object); const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockApiWrapper.object, mockExtensionContext.object);
const children = await treeDataProvider.getChildren(); const children = await treeDataProvider.getChildren();
@@ -125,7 +126,7 @@ describe('AzureResourceDatabaseTreeDataProvider.getChildren', function (): void
should(child.treeItem.contextValue).equal('azure.resource.itemType.databaseContainer'); should(child.treeItem.contextValue).equal('azure.resource.itemType.databaseContainer');
}); });
it('Should return resource nodes when it is container node.', async function (): Promise<void> { it('Should return resource nodes when it is container node.', async function(): Promise<void> {
const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockApiWrapper.object, mockExtensionContext.object); const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockApiWrapper.object, mockExtensionContext.object);
const children = await treeDataProvider.getChildren(mockResourceRootNode); const children = await treeDataProvider.getChildren(mockResourceRootNode);

View File

@@ -3,6 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should'; import * as should from 'should';
import * as TypeMoq from 'typemoq'; import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
@@ -30,8 +32,7 @@ const mockAccount: azdata.Account = {
displayInfo: { displayInfo: {
displayName: 'mock_account@test.com', displayName: 'mock_account@test.com',
accountType: 'Microsoft', accountType: 'Microsoft',
contextualDisplayName: 'test', contextualDisplayName: 'test'
userId: 'test@email.com'
}, },
properties: undefined, properties: undefined,
isStale: false isStale: false
@@ -57,7 +58,7 @@ const mockResourceRootNode: azureResource.IAzureResourceNode = {
} }
}; };
const mockTokens: { [key: string]: any } = {}; const mockTokens = {};
mockTokens[mockTenantId] = { mockTokens[mockTenantId] = {
token: 'mock_token', token: 'mock_token',
tokenType: 'Bearer' tokenType: 'Bearer'
@@ -78,14 +79,14 @@ const mockDatabaseServers: AzureResourceDatabaseServer[] = [
} }
]; ];
describe('AzureResourceDatabaseServerTreeDataProvider.info', function (): void { describe('AzureResourceDatabaseServerTreeDataProvider.info', function(): void {
beforeEach(() => { beforeEach(() => {
mockDatabaseServerService = TypeMoq.Mock.ofType<IAzureResourceDatabaseServerService>(); mockDatabaseServerService = TypeMoq.Mock.ofType<IAzureResourceDatabaseServerService>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>(); mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>(); mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
}); });
it('Should be correct when created.', async function (): Promise<void> { it('Should be correct when created.', async function(): Promise<void> {
const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockApiWrapper.object, mockExtensionContext.object); const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockApiWrapper.object, mockExtensionContext.object);
const treeItem = await treeDataProvider.getTreeItem(mockResourceRootNode); const treeItem = await treeDataProvider.getTreeItem(mockResourceRootNode);
@@ -96,7 +97,7 @@ describe('AzureResourceDatabaseServerTreeDataProvider.info', function (): void {
}); });
}); });
describe('AzureResourceDatabaseServerTreeDataProvider.getChildren', function (): void { describe('AzureResourceDatabaseServerTreeDataProvider.getChildren', function(): void {
beforeEach(() => { beforeEach(() => {
mockDatabaseServerService = TypeMoq.Mock.ofType<IAzureResourceDatabaseServerService>(); mockDatabaseServerService = TypeMoq.Mock.ofType<IAzureResourceDatabaseServerService>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>(); mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
@@ -107,7 +108,7 @@ describe('AzureResourceDatabaseServerTreeDataProvider.getChildren', function ():
mockExtensionContext.setup((o) => o.asAbsolutePath(TypeMoq.It.isAnyString())).returns(() => TypeMoq.It.isAnyString()); mockExtensionContext.setup((o) => o.asAbsolutePath(TypeMoq.It.isAnyString())).returns(() => TypeMoq.It.isAnyString());
}); });
it('Should return container node when element is undefined.', async function (): Promise<void> { it('Should return container node when element is undefined.', async function(): Promise<void> {
const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockApiWrapper.object, mockExtensionContext.object); const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockApiWrapper.object, mockExtensionContext.object);
const children = await treeDataProvider.getChildren(); const children = await treeDataProvider.getChildren();
@@ -125,7 +126,7 @@ describe('AzureResourceDatabaseServerTreeDataProvider.getChildren', function ():
should(child.treeItem.contextValue).equal('azure.resource.itemType.databaseServerContainer'); should(child.treeItem.contextValue).equal('azure.resource.itemType.databaseServerContainer');
}); });
it('Should return resource nodes when it is container node.', async function (): Promise<void> { it('Should return resource nodes when it is container node.', async function(): Promise<void> {
const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockApiWrapper.object, mockExtensionContext.object); const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockApiWrapper.object, mockExtensionContext.object);
const children = await treeDataProvider.getChildren(mockResourceRootNode); const children = await treeDataProvider.getChildren(mockResourceRootNode);

View File

@@ -23,8 +23,7 @@ const mockAccount: azdata.Account = {
displayInfo: { displayInfo: {
displayName: 'mock_account@test.com', displayName: 'mock_account@test.com',
accountType: 'Microsoft', accountType: 'Microsoft',
contextualDisplayName: 'test', contextualDisplayName: 'test'
userId: 'test@email.com'
}, },
properties: undefined, properties: undefined,
isStale: false isStale: false

View File

@@ -26,8 +26,7 @@ const mockAccount: azdata.Account = {
displayInfo: { displayInfo: {
displayName: 'mock_account@test.com', displayName: 'mock_account@test.com',
accountType: 'Microsoft', accountType: 'Microsoft',
contextualDisplayName: 'test', contextualDisplayName: 'test'
userId: 'test@email.com'
}, },
properties: undefined, properties: undefined,
isStale: false isStale: false

Some files were not shown because too many files have changed in this diff Show More