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
},
"osx": {
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh",
"timeout": 20000
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh"
},
"linux": {
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh",
"timeout": 20000
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh"
},
"env": {
"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",
"task": "tslint",

View File

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

View File

@@ -1,18 +1,5 @@
# 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
* Release date: March 18, 2019
* 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
-- | --
Windows User Installer | https://go.microsoft.com/fwlink/?linkid=2087316
Windows System Installer | https://go.microsoft.com/fwlink/?linkid=2087317
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=2087318
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=2087170
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=2087414
Linux RPM | https://go.microsoft.com/fwlink/?linkid=2087171
Linux DEB | https://go.microsoft.com/fwlink/?linkid=2087415
Windows User Installer | https://go.microsoft.com/fwlink/?linkid=2083322
Windows System Installer | https://go.microsoft.com/fwlink/?linkid=2083323
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=2083324
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=2083325
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=2083424
Linux RPM | https://go.microsoft.com/fwlink/?linkid=2083326
Linux DEB | https://go.microsoft.com/fwlink/?linkid=2083327
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"
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`
* AlexFsmn for `Added context menu for DBs in explorer view to backup & restore db. #2277`
* sadedil for `Missing feature request: Save as XML #3729`

View File

@@ -24,15 +24,21 @@ steps:
- script: |
yarn
displayName: 'Install'
displayName: 'Install'
- script: |
yarn gulp electron-x64
displayName: Download Electron
node_modules/.bin/gulp electron
node_modules/.bin/gulp compile --max_old_space_size=4096
displayName: 'Scripts'
- script: |
yarn gulp hygiene
displayName: Run Hygiene Checks
DISPLAY=:10 ./scripts/test.sh --reporter mocha-junit-reporter
displayName: 'Tests'
- task: PublishTestResults@2
inputs:
testResultsFiles: '**/test-results.xml'
condition: succeededOrFailed()
- script: |
yarn tslint
@@ -41,29 +47,3 @@ steps:
- script: |
yarn 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'
- script: |
yarn gulp electron-x64
.\node_modules\.bin\gulp electron
displayName: 'Electron'
- script: |
yarn gulp hygiene
displayName: Run Hygiene Checks
npm run compile
displayName: 'Compile'
- script: |
.\scripts\test.bat --reporter mocha-junit-reporter
displayName: 'Test'
- task: PublishTestResults@2
inputs:
testResultsFiles: 'test-results.xml'
condition: succeededOrFailed()
- script: |
yarn tslint
@@ -23,22 +32,3 @@ steps:
- script: |
yarn 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;
type: string;
url: string;
mooncakeUrl?: string;
// {{SQL CARBON EDIT}}
mooncakeUrl: string | undefined;
hash: string;
sha256hash: string;
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']!)
.withFilter(new azure.ExponentialRetryPolicyFilter(20));
// {{SQL CARBON EDIT}}
await assertContainer(blobService, quality);
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.`);
return;
}
console.log('Uploading blobs to Azure storage...');
await uploadBlob(blobService, quality, blobName, file);
await Promise.all(promises);
console.log('Blobs successfully uploaded.');
@@ -211,6 +250,8 @@ async function publish(commit: string, quality: string, platform: string, type:
platform: platform,
type: type,
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,
sha256hash,
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)
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 gulp mixin
yarn gulp hygiene
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" yarn gulp -- mixin
yarn gulp -- hygiene
yarn monaco-compile-check
node build/azure-pipelines/common/installDistro.js
node build/lib/builtInExtensions.js
@@ -36,7 +30,10 @@ steps:
set -e
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
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
- script: |
@@ -46,11 +43,6 @@ steps:
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-darwin/$APP_NAME"
displayName: Run unit tests
- script: |
set -e
./scripts/test-integration.sh --build --tfs "Integration Tests"
displayName: Run integration tests
- script: |
set -e
pushd ../VSCode-darwin && zip -r -X -y ../VSCode-darwin.zip * && popd
@@ -77,12 +69,31 @@ steps:
- script: |
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_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \
./build/azure-pipelines/darwin/publish.sh
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
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
- 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)
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
yarn gulp mixin
yarn gulp hygiene
yarn monaco-compile-check
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- mixin
npm run gulp -- hygiene
npm run monaco-compile-check
node build/azure-pipelines/common/installDistro.js
node build/lib/builtInExtensions.js
displayName: Prepare build
- script: |
set -e
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
./build/azure-pipelines/linux/build.sh
displayName: Build
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- vscode-linux-$(VSCODE_ARCH)-min
name: build
- script: |
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
service xvfb start
DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests"
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)"
displayName: Run unit tests
name: test
- script: |
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_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \
./build/azure-pipelines/linux/publish.sh
displayName: Publish
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
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
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
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
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" "linux-snap-$ARCH" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH"

View File

@@ -62,18 +62,4 @@ jobs:
pool:
vmImage: macOS 10.13
steps:
- 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
- template: darwin/product-build-darwin.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
$env:npm_config_arch="$(VSCODE_ARCH)"
$env:CHILD_CONCURRENCY="1"
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") }
$env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)"
exec { yarn }
exec { yarn gulp mixin }
exec { yarn gulp hygiene }
exec { yarn monaco-compile-check }
exec { npm run gulp -- mixin }
exec { npm run gulp -- hygiene }
exec { npm run monaco-compile-check }
exec { node build/azure-pipelines/common/installDistro.js }
exec { node build/lib/builtInExtensions.js }
displayName: Prepare build
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
$env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)"
.\build\azure-pipelines\win32\build.ps1
displayName: Build
exec { npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-min" }
exec { npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-inno-updater" }
name: build
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
exec { yarn gulp "electron-$(VSCODE_ARCH)" }
exec { npm run gulp -- "electron-$(VSCODE_ARCH)" }
exec { .\scripts\test.bat --build --tfs "Unit Tests" }
# yarn smoketest -- --build "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)"
displayName: Run unit tests
- 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
name: test
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
inputs:
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'
signConfigType: inlineSignParams
inlineOperation: |
@@ -132,11 +119,32 @@ steps:
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$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:MOONCAKE_STORAGE_ACCESS_KEY = "$(MOONCAKE_STORAGE_ACCESS_KEY)"
$env:AZURE_DOCUMENTDB_MASTERKEY = "$(AZURE_DOCUMENTDB_MASTERKEY)"
$env:VSCODE_HOCKEYAPP_TOKEN = "$(VSCODE_HOCKEYAPP_TOKEN)"
.\build\azure-pipelines\win32\publish.ps1
displayName: Publish
$assetPlatform = if ("$(VSCODE_ARCH)" -eq "ia32") { "win32" } else { "win32-x64" }
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
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/**/*.config',
'!**/Dockerfile',
'!**/Dockerfile.*',
'!**/*.Dockerfile',
'!**/*.dockerfile',
'!extensions/markdown-language-features/media/*.js',
// {{SQL CARBON EDIT}}
'!**/*.xlf',
'!**/*.docx',
'!**/*.sql',
'!extensions/mssql/sqltoolsservice/**',
'!extensions/import/flatfileimportservice/**',
'!extensions/markdown-language-features/media/*.js'
];
const copyrightFilter = [
@@ -125,37 +118,7 @@ const copyrightFilter = [
'!resources/completions/**',
'!extensions/markdown-language-features/media/highlight.css',
'!extensions/html-language-features/server/src/modes/typescript/*',
'!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'
'!extensions/*/server/bin/*'
];
const eslintFilter = [
@@ -201,7 +164,8 @@ gulp.task('eslint', () => {
});
gulp.task('tslint', () => {
const options = { emitError: true };
// {{SQL CARBON EDIT}}
const options = { emitError: false };
return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
.pipe(filter(tslintFilter))
@@ -299,8 +263,9 @@ function hygiene(some) {
.pipe(filter(f => !f.stat.isDirectory()))
.pipe(filter(indentationFilter))
.pipe(indentation)
.pipe(filter(copyrightFilter))
.pipe(copyrights);
.pipe(filter(copyrightFilter));
// {{SQL CARBON EDIT}}
// .pipe(copyrights);
const typescript = result
.pipe(filter(tslintFilter))
@@ -310,38 +275,15 @@ function hygiene(some) {
const javascript = result
.pipe(filter(eslintFilter))
.pipe(gulpeslint('src/.eslintrc'))
.pipe(gulpeslint.formatEach('compact'))
.pipe(gulpeslint.failAfterError());
.pipe(gulpeslint.formatEach('compact'));
// {{SQL CARBON EDIT}}
// .pipe(gulpeslint.failAfterError());
let count = 0;
return es.merge(typescript, javascript)
.pipe(es.through(function (data) {
count++;
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');
}
// {{SQL CARBON EDIT}}
this.emit('end');
}));
}

View File

@@ -6,12 +6,21 @@
'use strict';
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}}
const jeditor = require('gulp-json-editor');
gulp.task('mixin', function () {
// {{SQL CARBON EDIT}}
// {{SQL CARBON EDIT}}
const updateUrl = process.env['SQLOPS_UPDATEURL'];
if (!updateUrl) {
console.log('Missing SQLOPS_UPDATEURL, skipping mixin');

View File

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

View File

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

View File

@@ -27,7 +27,7 @@ function getDebPackageArch(arch) {
}
function prepareDebPackage(arch) {
// {{SQL CARBON EDIT}}
// {{SQL CARBON EDIT}}
const binaryDir = '../azuredatastudio-linux-' + arch;
const debArch = getDebPackageArch(arch);
const destination = '.build/linux/deb/' + debArch + '/' + product.applicationName + '-' + debArch;

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 issPath = path.join(__dirname, 'win32', 'code.iss');
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) {
options = options || {};

View File

@@ -237,7 +237,6 @@ exports.fromMarketplace = fromMarketplace;
const excludedExtensions = [
'vscode-api-tests',
'vscode-colorize-tests',
'vscode-test-resolver',
'ms-vscode.node-debug',
'ms-vscode.node-debug2',
// {{SQL CARBON EDIT}}
@@ -253,10 +252,9 @@ const sqlBuiltInExtensions = [
'profiler',
'admin-pack',
'big-data-cluster',
'dacpac',
'schema-compare',
'cms'
'dacpac'
];
var azureExtensions = ['azurecore', 'mssql'];
const builtInExtensions = require('../builtInExtensions.json');
/**
* 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 }) => builtInExtensions.every(b => b.name !== name))
// {{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 => () => {
return fromLocal(extension.path, opts.sourceMappingURLBase)
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));

View File

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

View File

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

View File

@@ -24,7 +24,7 @@ function log(message: any, ...rest: any[]): void {
}
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)
folderName?: string; // language specific folder name, e.g. cht, deu (optional, if not set, the id is used)
}
@@ -1378,4 +1378,4 @@ function decodeEntities(value: string): string {
function pseudify(message: string) {
return '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D';
}
}

View File

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

View File

@@ -1,7 +1,7 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* 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 });
const ts = require("typescript");

View File

@@ -1,6 +1,6 @@
/*---------------------------------------------------------------------------------------------
* 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';

View File

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

View File

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

View File

@@ -8,7 +8,7 @@
"resolveJsonModule": true,
"experimentalDecorators": true,
// 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
"allowJs": true,
"checkJs": true,
@@ -22,4 +22,4 @@
"exclude": [
"node_modules/**"
]
}
}

View File

@@ -70,7 +70,7 @@ Type: files; Name: "{app}\resources\app\Credits_45.0.2454.85.html"; Check: IsNot
Type: filesandordirs; Name: "{app}\_"
[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: "associatewithfiles"; Description: "{cm:AssociateWithFiles,{#NameLong}}"; GroupDescription: "{cm:Other}"; Flags: unchecked
Name: "addtopath"; Description: "{cm:AddToPath}"; GroupDescription: "{cm:Other}"

View File

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

View File

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

View File

@@ -1,75 +1,61 @@
{
"name": "admin-tool-ext-win",
"displayName": "%adminToolExtWin.displayName%",
"description": "%adminToolExtWin.description%",
"version": "0.0.1",
"publisher": "Microsoft",
"preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
"icon": "images/sqlserver.png",
"aiKey": "AIF-5574968e-856d-40d2-af67-c89a14e76412",
"engines": {
"vscode": "^1.30.1",
"sqlops": "*"
},
"activationEvents": [
"*"
],
"main": "./out/main",
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/azuredatastudio.git"
},
"extensionDependencies": [
"Microsoft.mssql"
],
"contributes": {
"commands": [
{
"command": "adminToolExtWin.launchSsmsMinPropertiesDialog",
"title": "%adminToolExtWin.propertiesMenuItem%",
"category": "AdminToolExtWin"
},
{
"command": "adminToolExtWin.launchSsmsMinGswDialog",
"title": "%adminToolExtWin.launchGswMenuItem%",
"category": "AdminToolExtWin"
}
],
"menus": {
"commandPalette": [
{
"command": "adminToolExtWin.launchSsmsMinPropertiesDialog",
"when": "false"
},
{
"command": "adminToolExtWin.launchSsmsMinGswDialog",
"when": "false"
}
],
"objectExplorer/item/context": [
{
"command": "adminToolExtWin.launchSsmsMinGswDialog",
"when": "isWindows && connectionProvider == MSSQL && nodeType && nodeType == Database",
"group": "z-AdminToolExt@1"
},
{
"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"
}
]
},
"outputChannels": [
"admin-tool-ext-win"
]
},
"dependencies": {
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
"vscode-extension-telemetry": "^0.0.15",
"vscode-nls": "^3.2.1"
},
"devDependencies": {
"vscode": "1.0.1"
}
}
"name": "admin-tool-ext-win",
"displayName": "Database Admin Tool Extensions for Windows",
"description": "Adds additional Windows-specific functionality to Azure Data Studio",
"version": "0.0.1",
"publisher": "Microsoft",
"preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
"icon": "images/sqlserver.png",
"aiKey": "AIF-5574968e-856d-40d2-af67-c89a14e76412",
"engines": {
"vscode": "^1.30.1",
"sqlops": "*"
},
"activationEvents": [
"*"
],
"main": "./out/main",
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/azuredatastudio.git"
},
"extensionDependencies": [
"Microsoft.mssql"
],
"contributes": {
"commands": [
{
"command": "adminToolExtWin.launchSsmsServerPropertiesDialog",
"title": "%adminToolExtWin.launchSsmsServerPropertiesDialog%",
"category": "AdminToolExtWin"
}
],
"menus": {
"commandPalette": [
{
"command": "adminToolExtWin.launchSsmsServerPropertiesDialog",
"when": "false"
}
],
"objectExplorer/item/context": [
{
"command": "adminToolExtWin.launchSsmsServerPropertiesDialog",
"when": "isWindows && connectionProvider == MSSQL && nodeType && nodeType == Server",
"group": "AdminToolExtWin"
}
]
},
"outputChannels": [
"admin-tool-ext-win"
]
},
"dependencies": {
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
"vscode-extension-telemetry": "^0.0.15",
"vscode-nls": "^3.2.1"
},
"devDependencies": {
"vscode": "1.0.1"
}
}

View File

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

View File

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

View File

@@ -2,6 +2,8 @@
* 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 nls from 'vscode-nls';
import * as path from 'path';
@@ -9,51 +11,15 @@ import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { IConfig, ServerProvider } from 'service-downloader';
import { Telemetry } from './telemetry';
import { doubleEscapeSingleQuotes, backEscapeDoubleQuotes, getConfiguration } from './utils';
import { ChildProcess, exec } from 'child_process';
import * as utils from './utils';
import { ChildProcess, exec, ExecException } from 'child_process';
import { stringify } from 'querystring';
const baseConfig = require('./config.json');
const localize = nls.loadMessageBundle();
let exePath: string;
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
// action used. Exported for use in testing.
export interface LaunchSsmsDialogParams {
@@ -61,6 +27,7 @@ export interface LaunchSsmsDialogParams {
server: string;
database?: string;
user?: string;
password?: string;
useAad?: boolean;
urn?: string;
}
@@ -72,8 +39,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
let config: IConfig = JSON.parse(JSON.stringify(baseConfig));
config.installDirectory = path.join(context.extensionPath, config.installDirectory);
config.proxy = getConfiguration('http').get('proxy');
config.strictSSL = getConfiguration('http').get('proxyStrictSSL') || true;
config.proxy = utils.getConfiguration('http').get('proxy');
config.strictSSL = utils.getConfiguration('http').get('proxyStrictSSL') || true;
const serverdownloader = new ServerProvider(config);
const installationStart = Date.now();
@@ -88,9 +55,9 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
} else {
throw new Error('Could not find SsmsMin.exe after downloading');
}
// Register the commands now that we have the exePath to run the tool with
registerCommands(context);
// Add the command now that we have the exePath to run the tool with
context.subscriptions.push(
vscode.commands.registerCommand('adminToolExtWin.launchSsmsServerPropertiesDialog', handleLaunchSsmsServerPropertiesDialogCommand));
Telemetry.sendTelemetryEvent('startup/ExtensionStarted', {
installationTime: String(installationComplete - installationStart),
@@ -111,56 +78,16 @@ export async function deactivate(): Promise<void> {
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
* @param connectionId The connection context from the command
*/
async function handleLaunchSsmsMinPropertiesDialogCommand(connectionContext?: azdata.ObjectExplorerContext): Promise<void> {
if (!connectionContext) {
vscode.window.showErrorMessage(localize('adminToolExtWin.noConnectionContextForProp', 'No ConnectionContext provided for handleLaunchSsmsMinPropertiesDialogCommand'));
return;
function handleLaunchSsmsServerPropertiesDialogCommand(connectionContext?: azdata.ObjectExplorerContext) {
if (connectionContext && connectionContext.connectionProfile) {
launchSsmsDialog(
/*action*/'sqla:Properties@Microsoft.SqlServer.Management.Smo.Server',
/*connectionProfile*/connectionContext.connectionProfile);
}
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(
nodeTypeToUrnNameMapping[nodeType].action,
connectionContext);
}
/**
* 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 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) {
vscode.window.showErrorMessage(localize('adminToolExtWin.noExeError', 'Unable to find SsmsMin.exe.'));
return;
}
if (!connectionContext.connectionProfile) {
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];
}
Telemetry.sendTelemetryEvent('LaunchSsmsDialog', { 'action': action });
let params: LaunchSsmsDialogParams = {
action: action,
server: connectionContext.connectionProfile.serverName,
database: connectionContext.connectionProfile.databaseName,
user: connectionContext.connectionProfile.userName,
useAad: connectionContext.connectionProfile.authenticationType === 'AzureMFA',
server: connectionProfile.serverName,
database: connectionProfile.databaseName,
password: connectionProfile.password,
user: connectionProfile.userName,
useAad: connectionProfile.authenticationType === 'AzureMFA',
urn: urn
};
let args = buildSsmsMinCommandArgs(params);
Telemetry.sendTelemetryEvent('LaunchSsmsDialog', { 'action': action });
// This will be an async call since we pass in the callback
let proc: ChildProcess = exec(
/*command*/ `"${exePath}" ${args}`,
/*options*/ undefined,
var proc: ChildProcess = exec(
/*command*/`"${exePath}" ${args}`,
/*options*/undefined,
(execException, stdout, stderr) => {
// Process has exited so remove from map of running processes
runningProcesses.delete(proc.pid);
@@ -244,15 +128,13 @@ async function launchSsmsDialog(action: string, connectionContext: azdata.Object
});
let err = stderr.toString();
if (err !== '') {
vscode.window.showErrorMessage(localize(
'adminToolExtWin.ssmsMinError',
'Error calling SsmsMin with args \'{0}\' - {1}', args, err));
console.warn(`Error calling SsmsMin with args '${args}' - ${err}`);
}
});
// If we're not using AAD the tool prompts for a password on stdin
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
@@ -266,34 +148,10 @@ async function launchSsmsDialog(action: string, connectionContext: azdata.Object
* @param params The params used to build up the command parameter string
*/
export function buildSsmsMinCommandArgs(params: LaunchSsmsDialogParams): string {
return `${params.action ? '-a "' + backEscapeDoubleQuotes(params.action) + '"' : ''}\
${params.server ? ' -S "' + backEscapeDoubleQuotes(params.server) + '"' : ''}\
${params.database ? ' -D "' + backEscapeDoubleQuotes(params.database) + '"' : ''}\
${params.useAad !== true && params.user ? ' -U "' + backEscapeDoubleQuotes(params.user) + '"' : ''}\
return `${params.action ? '-a "' + params.action.replace(/"/g, '\\"') + '"' : ''}\
${params.server ? ' -S "' + params.server.replace(/"/g, '\\"') + '"' : ''}\
${params.database ? ' -D "' + params.database.replace(/"/g, '\\"') + '"' : ''}\
${params.useAad !== true && params.user ? ' -U "' + params.user.replace(/"/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

@@ -13,123 +13,123 @@ import * as Utils from './utils';
const packageJson = require('../package.json');
export interface ITelemetryEventProperties {
[key: string]: string;
[key: string]: string;
}
export interface ITelemetryEventMeasures {
[key: string]: number;
[key: string]: number;
}
/**
* Filters error paths to only include source files. Exported to support testing
*/
export function filterErrorPath(line: string): string {
if (line) {
let values: string[] = line.split('/out/');
if (values.length <= 1) {
// Didn't match expected format
return line;
} else {
return values[1];
}
}
if (line) {
let values: string[] = line.split('/out/');
if (values.length <= 1) {
// Didn't match expected format
return line;
} else {
return values[1];
}
}
}
export class Telemetry {
private static reporter: TelemetryReporter;
private static userId: string;
private static platformInformation: PlatformInformation;
private static disabled: boolean;
private static reporter: TelemetryReporter;
private static userId: string;
private static platformInformation: PlatformInformation;
private static disabled: boolean;
public static getPlatformInformation(): Promise<PlatformInformation> {
if (this.platformInformation) {
return Promise.resolve(this.platformInformation);
} else {
return new Promise<PlatformInformation>(resolve => {
PlatformInformation.getCurrent().then(info => {
this.platformInformation = info;
resolve(this.platformInformation);
});
});
}
}
public static getPlatformInformation(): Promise<PlatformInformation> {
if (this.platformInformation) {
return Promise.resolve(this.platformInformation);
} else {
return new Promise<PlatformInformation>(resolve => {
PlatformInformation.getCurrent().then(info => {
this.platformInformation = info;
resolve(this.platformInformation);
});
});
}
}
/**
* Disable telemetry reporting
*/
public static disable(): void {
this.disabled = true;
}
/**
* Disable telemetry reporting
*/
public static disable(): void {
this.disabled = true;
}
/**
* Initialize the telemetry reporter for use.
*/
public static initialize(): void {
if (typeof this.reporter === 'undefined') {
// Check if the user has opted out of telemetry
if (!vscode.workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry', true)) {
this.disable();
return;
}
/**
* Initialize the telemetry reporter for use.
*/
public static initialize(): void {
if (typeof this.reporter === 'undefined') {
// Check if the user has opted out of telemetry
if (!vscode.workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry', true)) {
this.disable();
return;
}
let packageInfo = Utils.getPackageInfo(packageJson);
this.reporter = new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
}
}
let packageInfo = Utils.getPackageInfo(packageJson);
this.reporter = new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
}
}
/**
* Send a telemetry event for an exception
*/
public static sendTelemetryEventForException(
err: any, methodName: string, extensionConfigName: string): void {
try {
let stackArray: string[];
let firstLine: string = '';
if (err !== undefined && err.stack !== undefined) {
stackArray = err.stack.split('\n');
if (stackArray !== undefined && stackArray.length >= 2) {
firstLine = stackArray[1]; // The first line is the error message and we don't want to send that telemetry event
firstLine = filterErrorPath(firstLine);
}
}
/**
* Send a telemetry event for an exception
*/
public static sendTelemetryEventForException(
err: any, methodName: string, extensionConfigName: string): void {
try {
let stackArray: string[];
let firstLine: string = '';
if (err !== undefined && err.stack !== undefined) {
stackArray = err.stack.split('\n');
if (stackArray !== undefined && stackArray.length >= 2) {
firstLine = stackArray[1]; // The first line is the error message and we don't want to send that telemetry event
firstLine = filterErrorPath(firstLine);
}
}
// Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII
this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine });
} catch (telemetryErr) {
// If sending telemetry event fails ignore it so it won't break the extension
console.error('Failed to send telemetry event. error: ' + telemetryErr, extensionConfigName);
}
}
// Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII
this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine });
} catch (telemetryErr) {
// If sending telemetry event fails ignore it so it won't break the extension
console.error('Failed to send telemetry event. error: ' + telemetryErr, extensionConfigName);
}
}
/**
* Send a telemetry event using application insights
*/
public static sendTelemetryEvent(
eventName: string,
properties?: ITelemetryEventProperties,
measures?: ITelemetryEventMeasures): void {
/**
* Send a telemetry event using application insights
*/
public static sendTelemetryEvent(
eventName: string,
properties?: ITelemetryEventProperties,
measures?: ITelemetryEventMeasures): void {
if (typeof this.disabled === 'undefined') {
this.disabled = false;
}
if (typeof this.disabled === 'undefined') {
this.disabled = false;
}
if (this.disabled || typeof (this.reporter) === 'undefined') {
// Don't do anything if telemetry is disabled
return;
}
if (this.disabled || typeof (this.reporter) === 'undefined') {
// Don't do anything if telemetry is disabled
return;
}
if (!properties || typeof properties === 'undefined') {
properties = {};
}
if (!properties || typeof properties === 'undefined') {
properties = {};
}
// Augment the properties structure with additional common properties before sending
Promise.all([this.getPlatformInformation()]).then(() => {
properties['distribution'] = (this.platformInformation && this.platformInformation.distribution) ?
`${this.platformInformation.distribution.name}, ${this.platformInformation.distribution.version}` : '';
// Augment the properties structure with additional common properties before sending
Promise.all([this.getPlatformInformation()]).then(() => {
properties['distribution'] = (this.platformInformation && this.platformInformation.distribution) ?
`${this.platformInformation.distribution.name}, ${this.platformInformation.distribution.version}` : '';
this.reporter.sendTelemetryEvent(eventName, properties, measures);
});
}
this.reporter.sendTelemetryEvent(eventName, properties, measures);
});
}
}
Telemetry.initialize();

View File

@@ -9,20 +9,20 @@ const testRunner = require('vscode/lib/testrunner');
const suite = 'Database Admin Tool Extensions for Windows';
const options: any = {
ui: 'bdd',
useColors: true,
timeout: 600000
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`)
}
};
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);

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 'mocha';
import { buildSsmsMinCommandArgs, buildUrn, LaunchSsmsDialogParams } from '../main';
import { doubleEscapeSingleQuotes, backEscapeDoubleQuotes } from '../utils';
import { ExtHostObjectExplorerNodeStub } from './stubs';
import * as extensionMain from '../main';
describe('buildSsmsMinCommandArgs Method Tests', () => {
it('Should be built correctly with all params and UseAAD as false', function (): void {
const params: LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer',
database: 'myDatabase',
user: 'user',
useAad: false,
urn: 'Server\\Database\\Table'
};
const args = buildSsmsMinCommandArgs(params);
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 false', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer',
database: 'myDatabase',
user: 'user',
password: 'password',
useAad: false,
urn: 'Server\\Database\\Table'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
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 {
const params: LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer',
database: 'myDatabase',
user: 'user',
useAad: true,
urn: 'Server\\Database\\Table'
};
const args = buildSsmsMinCommandArgs(params);
// User is omitted since UseAAD is true
should(args).equal('-a "myAction" -S "myServer" -D "myDatabase" -G -u "Server\\Database\\Table"');
});
it('Should be built correctly with all params and UseAAD as true', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer',
database: 'myDatabase',
user: 'user',
password: 'password',
useAad: true,
urn: 'Server\\Database\\Table'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
// User is omitted since UseAAD is true
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 {
const params: LaunchSsmsDialogParams = {
action: 'myAction\'"/\\[]tricky',
server: 'myServer\'"/\\[]tricky',
database: 'myDatabase\'"/\\[]tricky',
user: 'user\'"/\\[]tricky',
useAad: true,
urn: 'Server\\Database[\'myDatabase\'\'"/\\[]tricky\']\\Table["myTable\'""/\\[]tricky"]'
};
const args = buildSsmsMinCommandArgs(params);
// 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\\"]"');
});
it('Should be built correctly and names escaped correctly', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction\'"/\\[]tricky',
server: 'myServer\'"/\\[]tricky',
database: 'myDatabase\'"/\\[]tricky',
user: 'user\'"/\\[]tricky',
password: 'password',
useAad: true,
urn: 'Server\\Database[\'myDatabase\'\'"/\\[]tricky\']\\Table["myTable\'""/\\[]tricky"]'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
// 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\\"]"');
});
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 = {
action: 'myAction',
server: 'myServer'
};
const args = buildSsmsMinCommandArgs(params);
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');
});
let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
should(args).equal('-a "myAction" -S "myServer"');
});
});

View File

@@ -7,19 +7,19 @@
import * as vscode from 'vscode';
export interface IPackageInfo {
name: string;
version: string;
aiKey: string;
name: string;
version: string;
aiKey: string;
}
export function getPackageInfo(packageJson: any): IPackageInfo {
if (packageJson) {
return {
name: packageJson.name,
version: packageJson.version,
aiKey: packageJson.aiKey
};
}
if (packageJson) {
return {
name: packageJson.name,
version: packageJson.version,
aiKey: packageJson.aiKey
};
}
}
/**
@@ -28,33 +28,15 @@ export function getPackageInfo(packageJson: any): IPackageInfo {
* @param resource The optional URI, as a URI object or a string, to use to get resource-scoped configurations
*/
export function getConfiguration(extensionName?: string, resource?: vscode.Uri | string): vscode.WorkspaceConfiguration {
if (typeof resource === 'string') {
try {
resource = this.parseUri(resource);
} catch (e) {
resource = undefined;
}
} else if (!resource) {
// Fix to avoid adding lots of errors to debug console. Expects a valid resource or null, not undefined
resource = null;
}
return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri);
if (typeof resource === 'string') {
try {
resource = this.parseUri(resource);
} catch (e) {
resource = undefined;
}
} else if (!resource) {
// Fix to avoid adding lots of errors to debug console. Expects a valid resource or null, not undefined
resource = null;
}
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, '\\"');
}

View File

@@ -1,22 +1,22 @@
{
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "./out",
"lib": [
"es6", "es2015.promise"
],
"typeRoots": [
"./node_modules/@types"
],
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"declaration": true
},
"exclude": [
"node_modules"
]
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "./out",
"lib": [
"es6", "es2015.promise"
],
"typeRoots": [
"./node_modules/@types"
],
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"declaration": true
},
"exclude": [
"node_modules"
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,14 +2,14 @@
"name": "agent",
"displayName": "SQL Server Agent",
"description": "Manage and troubleshoot SQL Server Agent jobs",
"version": "0.39.0",
"version": "0.37.0",
"publisher": "Microsoft",
"preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
"icon": "images/sqlserver.png",
"aiKey": "AIF-5574968e-856d-40d2-af67-c89a14e76412",
"engines": {
"vscode": "^1.25.0"
"vscode": "0.10.x"
},
"activationEvents": [
"*"
@@ -46,13 +46,7 @@
},
"devDependencies": {
"mocha-junit-reporter": "^1.17.0",
"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"
"mocha-multi-reporters": "^1.1.7"
},
"__metadata": {
"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';
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.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import * as data from 'azdata';
@@ -11,51 +12,52 @@ import * as data from 'azdata';
* this API from our code
*
* @export
* @class ApiWrapper
*/
export class ApiWrapper {
// Data APIs
// Data APIs
public registerWebviewProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void {
return data.dashboard.registerWebviewProvider(widgetId, handler);
}
public registerWebviewProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void {
return data.dashboard.registerWebviewProvider(widgetId, handler);
}
public registerControlHostProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void {
return data.dashboard.registerWebviewProvider(widgetId, handler);
}
public registerControlHostProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void {
return data.dashboard.registerWebviewProvider(widgetId, handler);
}
/**
* Get the configuration for a extensionName
* @param extensionName The string name of the extension to get the configuration for
* @param resource The optional URI, as a URI object or a string, to use to get resource-scoped configurations
*/
public getConfiguration(extensionName: string, resource?: vscode.Uri | string): vscode.WorkspaceConfiguration {
if (typeof resource === 'string') {
try {
resource = this.parseUri(resource);
} catch (e) {
resource = undefined;
}
}
return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri);
}
/**
* Get the configuration for a extensionName
* @param extensionName The string name of the extension to get the configuration for
* @param resource The optional URI, as a URI object or a string, to use to get resource-scoped configurations
*/
public getConfiguration(extensionName: string, resource?: vscode.Uri | string): vscode.WorkspaceConfiguration {
if (typeof resource === 'string') {
try {
resource = this.parseUri(resource);
} catch (e) {
resource = undefined;
}
}
return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri);
}
/**
* Parse uri
*/
public parseUri(uri: string): vscode.Uri {
return vscode.Uri.parse(uri);
}
/**
* Parse uri
*/
public parseUri(uri: string): vscode.Uri {
return vscode.Uri.parse(uri);
}
public showOpenDialog(options: vscode.OpenDialogOptions): Thenable<vscode.Uri[] | undefined> {
return vscode.window.showOpenDialog(options);
}
public showOpenDialog(options: vscode.OpenDialogOptions): Thenable<vscode.Uri[] | undefined> {
return vscode.window.showOpenDialog(options);
}
public showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> {
return vscode.window.showErrorMessage(message, ...items);
}
public showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> {
return vscode.window.showErrorMessage(message, ...items);
}
public get workspaceRootPath(): string {
return vscode.workspace.rootPath;
}
public get workspaceRootPath(): string {
return vscode.workspace.rootPath;
}
}

View File

@@ -17,7 +17,7 @@ export class AlertData implements IAgentDialogData {
public static readonly AlertTypeSqlServerEventString: string = localize('alertData.DefaultAlertTypString', 'SQL Server event alert');
public static readonly AlertTypePerformanceConditionString: string = localize('alertDialog.PerformanceCondition', 'SQL Server performance condition alert');
public static readonly AlertTypeWmiEventString: string = localize('alertDialog.WmiEvent', 'WMI event alert');
public static readonly DefaultAlertTypeString: string = AlertData.AlertTypeSqlServerEventString;
public static readonly DefaultAlertTypeString: string = AlertData.AlertTypeSqlServerEventString;
ownerUri: string;
dialogMode: AgentDialogMode = AgentDialogMode.CREATE;
@@ -50,7 +50,7 @@ export class AlertData implements IAgentDialogData {
private jobModel: JobData;
constructor(
ownerUri: string,
ownerUri:string,
alertInfo: azdata.AgentAlertInfo,
jobModel?: JobData,
viaJobDialog: boolean = false

View File

@@ -14,7 +14,7 @@ const localize = nls.loadMessageBundle();
export class JobData implements IAgentDialogData {
private readonly JobCompletionActionCondition_Always: string = localize('jobData.whenJobCompletes', 'When the job completes');
private readonly JobCompletionActionCondition_Always: string = localize('jobData.whenJobCompletes', 'When the job completes');
private readonly JobCompletionActionCondition_OnFailure: string = localize('jobData.whenJobFails', 'When the job fails');
private readonly JobCompletionActionCondition_OnSuccess: string = localize('jobData.whenJobSucceeds', 'When the job succeeds');
@@ -126,7 +126,7 @@ export class JobData implements IAgentDialogData {
public async save() {
let jobInfo: azdata.AgentJobInfo = this.toAgentJobInfo();
let result = this.dialogMode === AgentDialogMode.CREATE
? await this._agentService.createJob(this.ownerUri, jobInfo)
? await this._agentService.createJob(this.ownerUri, jobInfo)
: await this._agentService.updateJob(this.ownerUri, this.originalName, jobInfo);
if (!result || !result.success) {
if (this.dialogMode === AgentDialogMode.EDIT) {
@@ -142,7 +142,7 @@ export class JobData implements IAgentDialogData {
localize('jobData.saveSucessMessage', "Job '{0}' updated successfully", jobInfo.name));
} else {
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 viaJobDialog: boolean;
constructor(ownerUri: string, jobModel?: JobData, viaJobDialog: boolean = false) {
constructor(ownerUri:string, jobModel?: JobData, viaJobDialog: boolean = false) {
this.ownerUri = ownerUri;
this.jobName = jobModel.name;
this.jobModel = jobModel;
@@ -102,26 +102,26 @@ export class JobStepData implements IAgentDialogData {
stepData.jobName = jobStepInfo.jobName;
stepData.script = jobStepInfo.script;
stepData.scriptName = jobStepInfo.scriptName,
stepData.stepName = jobStepInfo.stepName,
stepData.subSystem = jobStepInfo.subSystem,
stepData.id = jobStepInfo.id,
stepData.failureAction = jobStepInfo.failureAction,
stepData.successAction = jobStepInfo.successAction,
stepData.failStepId = jobStepInfo.failStepId,
stepData.successStepId = jobStepInfo.successStepId,
stepData.command = jobStepInfo.command,
stepData.commandExecutionSuccessCode = jobStepInfo.commandExecutionSuccessCode,
stepData.databaseName = jobStepInfo.databaseName,
stepData.databaseUserName = jobStepInfo.databaseUserName,
stepData.server = jobStepInfo.server,
stepData.outputFileName = jobStepInfo.outputFileName,
stepData.appendToLogFile = jobStepInfo.appendToLogFile,
stepData.appendToStepHist = jobStepInfo.appendToStepHist,
stepData.writeLogToTable = jobStepInfo.writeLogToTable,
stepData.appendLogToTable = jobStepInfo.appendLogToTable,
stepData.retryAttempts = jobStepInfo.retryAttempts,
stepData.retryInterval = jobStepInfo.retryInterval,
stepData.proxyName = jobStepInfo.proxyName;
stepData.stepName = jobStepInfo.stepName,
stepData.subSystem = jobStepInfo.subSystem,
stepData.id = jobStepInfo.id,
stepData.failureAction = jobStepInfo.failureAction,
stepData.successAction = jobStepInfo.successAction,
stepData.failStepId = jobStepInfo.failStepId,
stepData.successStepId = jobStepInfo.successStepId,
stepData.command = jobStepInfo.command,
stepData.commandExecutionSuccessCode = jobStepInfo.commandExecutionSuccessCode,
stepData.databaseName = jobStepInfo.databaseName,
stepData.databaseUserName = jobStepInfo.databaseUserName,
stepData.server = jobStepInfo.server,
stepData.outputFileName = jobStepInfo.outputFileName,
stepData.appendToLogFile = jobStepInfo.appendToLogFile,
stepData.appendToStepHist = jobStepInfo.appendToStepHist,
stepData.writeLogToTable = jobStepInfo.writeLogToTable,
stepData.appendLogToTable = jobStepInfo.appendLogToTable,
stepData.retryAttempts = jobStepInfo.retryAttempts,
stepData.retryInterval = jobStepInfo.retryInterval,
stepData.proxyName = jobStepInfo.proxyName;
stepData.dialogMode = AgentDialogMode.EDIT;
stepData.viaJobDialog = true;
return stepData;

View File

@@ -29,7 +29,7 @@ export class OperatorData implements IAgentDialogData {
weekdayPagerStartTime: string;
weekdayPagerEndTime: string;
constructor(ownerUri: string, operatorInfo: azdata.AgentOperatorInfo) {
constructor(ownerUri:string, operatorInfo: azdata.AgentOperatorInfo) {
this.ownerUri = ownerUri;
if (operatorInfo) {
this.dialogMode = AgentDialogMode.EDIT;
@@ -58,7 +58,7 @@ export class OperatorData implements IAgentDialogData {
public async save() {
let agentService = await AgentUtils.getAgentService();
let result = await agentService.createOperator(this.ownerUri, this.toAgentOperatorInfo());
let result = await agentService.createOperator(this.ownerUri, this.toAgentOperatorInfo());
if (!result || !result.success) {
// TODO handle error here
}

View File

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

View File

@@ -22,7 +22,7 @@ export class ProxyData implements IAgentDialogData {
credentialId: number;
isEnabled: boolean;
constructor(ownerUri: string, proxyInfo: azdata.AgentProxyInfo) {
constructor(ownerUri:string, proxyInfo: azdata.AgentProxyInfo) {
this.ownerUri = ownerUri;
if (proxyInfo) {
@@ -48,7 +48,7 @@ export class ProxyData implements IAgentDialogData {
localize('proxyData.saveSucessMessage', "Proxy '{0}' updated successfully", proxyInfo.accountName));
} else {
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 selectedSchedule: azdata.AgentJobScheduleInfo;
constructor(ownerUri: string) {
constructor(ownerUri:string) {
this.ownerUri = ownerUri;
}

View File

@@ -62,14 +62,14 @@ export class AlertDialog extends AgentDialog<AlertData> {
private static readonly AlertSeverity025Label: string = localize('alertDialog.Severity025', '025 - Fatal Error');
private static readonly AllDatabases: string = localize('alertDialog.AllDatabases', '<all databases>');
private static readonly AlertTypes: string[] = [
private static readonly AlertTypes: string[] = [
AlertData.AlertTypeSqlServerEventString,
// Disabled until next release
// AlertData.AlertTypePerformanceConditionString,
// AlertData.AlertTypeWmiEventString
];
private static readonly AlertSeverities: string[] = [
private static readonly AlertSeverities: string[] = [
AlertDialog.AlertSeverity001Label,
AlertDialog.AlertSeverity002Label,
AlertDialog.AlertSeverity003Label,
@@ -100,21 +100,21 @@ export class AlertDialog extends AgentDialog<AlertData> {
// Response tab strings
private static readonly ExecuteJobCheckBoxLabel: string = localize('alertDialog.ExecuteJob', 'Execute Job');
private static readonly ExecuteJobTextBoxLabel: string = localize('alertDialog.ExecuteJobName', 'Job Name');
private static readonly NotifyOperatorsTextBoxLabel: string = localize('alertDialog.NotifyOperators', 'Notify Operators');
private static readonly NewJobButtonLabel: string = localize('alertDialog.NewJob', 'New Job');
private static readonly OperatorListLabel: string = localize('alertDialog.OperatorList', 'Operator List');
private static readonly OperatorNameColumnLabel: string = localize('alertDialog.OperatorName', 'Operator');
private static readonly OperatorEmailColumnLabel: string = localize('alertDialog.OperatorEmail', 'E-mail');
private static readonly OperatorPagerColumnLabel: string = localize('alertDialog.OperatorPager', 'Pager');
private static readonly NewOperatorButtonLabel: string = localize('alertDialog.NewOperator', 'New Operator');
private static readonly NotifyOperatorsTextBoxLabel: string = localize('alertDialog.NotifyOperators', 'Notify Operators');
private static readonly NewJobButtonLabel: string = localize('alertDialog.NewJob', 'New Job');
private static readonly OperatorListLabel: string = localize('alertDialog.OperatorList', 'Operator List');
private static readonly OperatorNameColumnLabel: string = localize('alertDialog.OperatorName', 'Operator');
private static readonly OperatorEmailColumnLabel: string = localize('alertDialog.OperatorEmail', 'E-mail');
private static readonly OperatorPagerColumnLabel: string = localize('alertDialog.OperatorPager', 'Pager');
private static readonly NewOperatorButtonLabel: string = localize('alertDialog.NewOperator', 'New Operator');
// Options tab strings
private static readonly IncludeErrorInEmailCheckBoxLabel: string = localize('alertDialog.IncludeErrorInEmail', 'Include alert error text in e-mail');
private static readonly IncludeErrorInPagerCheckBoxLabel: string = localize('alertDialog.IncludeErrorInPager', 'Include alert error text in pager');
private static readonly AdditionalMessageTextBoxLabel: string = localize('alertDialog.AdditionalNotification', 'Additional notification message to send');
private static readonly DelayBetweenResponsesTextBoxLabel: string = localize('alertDialog.DelayBetweenResponse', 'Delay between responses');
private static readonly DelayMinutesTextBoxLabel: string = localize('alertDialog.DelayMinutes', 'Delay Minutes');
private static readonly DelaySecondsTextBoxLabel: string = localize('alertDialog.DelaySeconds', 'Delay Seconds');
private static readonly IncludeErrorInEmailCheckBoxLabel: string = localize('alertDialog.IncludeErrorInEmail', 'Include alert error text in e-mail');
private static readonly IncludeErrorInPagerCheckBoxLabel: string = localize('alertDialog.IncludeErrorInPager', 'Include alert error text in pager');
private static readonly AdditionalMessageTextBoxLabel: string = localize('alertDialog.AdditionalNotification', 'Additional notification message to send');
private static readonly DelayBetweenResponsesTextBoxLabel: string = localize('alertDialog.DelayBetweenResponse', 'Delay between responses');
private static readonly DelayMinutesTextBoxLabel: string = localize('alertDialog.DelayMinutes', 'Delay Minutes');
private static readonly DelaySecondsTextBoxLabel: string = localize('alertDialog.DelaySeconds', 'Delay Seconds');
// Event Name strings
private readonly NewAlertDialog = 'NewAlertDialogOpen';
@@ -315,7 +315,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
}],
title: AlertDialog.EventAlertText
}
]).withLayout({ width: '100%' }).component();
]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel);
@@ -332,7 +332,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
if (this.model.severity > 0) {
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) {
@@ -356,9 +356,9 @@ export class AlertDialog extends AgentDialog<AlertData> {
.component();
this.executeJobTextBox.enabled = false;
this.newJobButton = view.modelBuilder.button().withProperties({
label: AlertDialog.NewJobButtonLabel,
width: 80
}).component();
label: AlertDialog.NewJobButtonLabel,
width: 80
}).component();
this.newJobButton.enabled = false;
this.newJobButton.onDidClick(() => {
let jobDialog = new JobDialog(this.ownerUri);
@@ -382,7 +382,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
}, {
component: this.newJobButton,
title: AlertDialog.NewJobButtonLabel
}], { componentWidth: '100%' }).component();
}], { componentWidth: '100%'}).component();
let previewTag = view.modelBuilder.text()
.withProperties({
@@ -409,9 +409,9 @@ export class AlertDialog extends AgentDialog<AlertData> {
}).component();
this.newOperatorButton = view.modelBuilder.button().withProperties({
label: AlertDialog.NewOperatorButtonLabel,
width: 80
}).component();
label: AlertDialog.NewOperatorButtonLabel,
width: 80
}).component();
this.operatorsTable.enabled = false;
this.newOperatorButton.enabled = false;
@@ -438,7 +438,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
}, {
component: this.newOperatorButton,
title: ''
}], { componentWidth: '100%' }).component();
}], { componentWidth: '100%'}).component();
let formModel = view.modelBuilder.formContainer()
.withFormItems([{
@@ -548,7 +548,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
} else {
this.model.eventDescriptionKeyword = '';
}
let minutes = this.delayMinutesTextBox.value ? +this.delayMinutesTextBox.value : 0;
let minutes = this.delayMinutesTextBox.value ? +this.delayMinutesTextBox.value : 0;
let seconds = this.delaySecondsTextBox.value ? +this.delaySecondsTextBox : 0;
this.model.delayBetweenResponses = minutes + seconds;

View File

@@ -70,7 +70,7 @@ export class JobDialog extends AgentDialog<JobData> {
// Event Name strings
private readonly NewJobDialogEvent: string = 'NewJobDialogOpened';
private readonly EditJobDialogEvent: string = 'EditJobDialogOpened';
private readonly EditJobDialogEvent: string = 'EditJobDialogOpened';
// UI Components
private generalTab: azdata.window.DialogTab;
@@ -259,9 +259,9 @@ export class JobDialog extends AgentDialog<JobData> {
width: 140
}).component();
this.newStepButton.onDidClick((e) => {
this.newStepButton.onDidClick((e)=>{
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) => {
let stepInfo = JobStepData.convertToAgentJobStepInfo(step);
this.steps.push(stepInfo);
@@ -296,7 +296,7 @@ export class JobDialog extends AgentDialog<JobData> {
this.deleteStepButton.enabled = false;
this.moveStepUpButton.onDidClick(() => {
let rowNumber = this.stepsTable.selectedRows[0];
let rowNumber = this.stepsTable.selectedRows[0];
let previousRow = rowNumber - 1;
let previousStep = this.steps[previousRow];
let previousStepId = this.steps[previousRow].id;
@@ -329,7 +329,7 @@ export class JobDialog extends AgentDialog<JobData> {
if (this.stepsTable.selectedRows.length === 1) {
let rowNumber = this.stepsTable.selectedRows[0];
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) => {
let stepInfo = JobStepData.convertToAgentJobStepInfo(step);
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) {
let rowNumber = this.stepsTable.selectedRows[0];
AgentUtils.getAgentService().then(async (agentService) => {
@@ -448,7 +448,7 @@ export class JobDialog extends AgentDialog<JobData> {
this.alerts.push(alertInfo);
this.alertsTable.data = this.convertAlertsToData(this.alerts);
});
this.newAlertButton.onDidClick(() => {
this.newAlertButton.onDidClick(()=>{
if (this.nameTextBox.value && this.nameTextBox.value.length > 0) {
alertDialog.jobId = this.model.jobId;
alertDialog.jobName = this.model.name ? this.model.name : this.nameTextBox.value;
@@ -491,7 +491,7 @@ export class JobDialog extends AgentDialog<JobData> {
label: 'Remove schedule',
width: 100
}).component();
this.pickScheduleButton.onDidClick(() => {
this.pickScheduleButton.onDidClick(()=>{
let pickScheduleDialog = new PickScheduleDialog(this.model.ownerUri, this.model.name);
pickScheduleDialog.onSuccess((dialogModel) => {
let selectedSchedule = dialogModel.selectedSchedule;
@@ -507,8 +507,8 @@ export class JobDialog extends AgentDialog<JobData> {
pickScheduleDialog.showDialog();
});
this.removeScheduleButton.onDidClick(() => {
if (this.schedulesTable.selectedRows.length === 1) {
let selectedRow = this.schedulesTable.selectedRows[0];
if (this.schedulesTable.selectedRows.length === 1) {
let selectedRow = this.schedulesTable.selectedRows[0];
let selectedScheduleName = this.schedulesTable.data[selectedRow][1];
for (let i = 0; i < this.schedules.length; i++) {
if (this.schedules[i].name === selectedScheduleName) {
@@ -595,23 +595,22 @@ export class JobDialog extends AgentDialog<JobData> {
let formModel = view.modelBuilder.formContainer().withFormItems([
{
components:
[{
component: emailContainer,
title: ''
},
{
component: pagerContainer,
title: ''
},
{
component: eventLogContainer,
title: ''
},
{
component: deleteJobContainer,
title: ''
}], title: this.NotificationsTabTopLabelString
}]).withLayout({ width: '100%' }).component();
[{
component: emailContainer,
title: ''
},
{
component: pagerContainer,
title: ''
},
{
component: eventLogContainer,
title: ''
},
{
component: deleteJobContainer,
title: ''
}], title: this.NotificationsTabTopLabelString}]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel);
this.emailConditionDropdown.values = this.model.JobCompletionActionConditions;
@@ -695,7 +694,7 @@ export class JobDialog extends AgentDialog<JobData> {
this.model.pageLevel = this.getActualConditionValue(this.pagerCheckBox, this.pagerConditionDropdown);
this.model.eventLogLevel = this.getActualConditionValue(this.eventLogCheckBox, this.eventLogConditionDropdown);
this.model.deleteLevel = this.getActualConditionValue(this.deleteJobCheckBox, this.deleteJobConditionDropdown);
this.model.startStepId = this.startStepDropdown.enabled ? +this.getDropdownValue(this.startStepDropdown) : 1;
this.model.startStepId = this.startStepDropdown.enabled ? +this.getDropdownValue(this.startStepDropdown) : 1;
if (!this.model.jobSteps) {
this.model.jobSteps = [];
}

View File

@@ -28,7 +28,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
private readonly GeneralTabText: string = localize('jobStepDialog.general', 'General');
private readonly AdvancedTabText: string = localize('jobStepDialog.advanced', 'Advanced');
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 FailureParseText: string = localize('jobStepDialog.failParse', 'The command failed.');
private readonly BlankStepNameErrorText: string = localize('jobStepDialog.blankStepName', 'The step name cannot be left blank');
@@ -124,15 +124,15 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
viaJobDialog: boolean = false
) {
super(ownerUri,
jobStepInfo ? JobStepData.convertToJobStepData(jobStepInfo, jobModel) : new JobStepData(ownerUri, jobModel, viaJobDialog),
jobStepInfo ? JobStepDialog.EditDialogTitle : JobStepDialog.NewDialogTitle);
jobStepInfo ? JobStepData.convertToJobStepData(jobStepInfo, jobModel) : new JobStepData(ownerUri, jobModel, viaJobDialog),
jobStepInfo ? JobStepDialog.EditDialogTitle : JobStepDialog.NewDialogTitle);
this.stepId = jobStepInfo ?
jobStepInfo.id : jobModel.jobSteps ?
jobModel.jobSteps.length + 1 : 1;
jobStepInfo.id : jobModel.jobSteps ?
jobModel.jobSteps.length + 1 : 1;
this.isEdit = jobStepInfo ? true : false;
this.model.dialogMode = this.isEdit ? AgentDialogMode.EDIT : AgentDialogMode.CREATE;
this.jobModel = jobModel;
this.jobName = this.jobName ? this.jobName : this.jobModel.name;
this.jobName = this.jobName ? this.jobName : this.jobModel.name;
this.server = server;
this.dialogName = this.isEdit ? this.EditStepDialog : this.NewStepDialog;
}
@@ -164,7 +164,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
if (this.commandTextBox.value) {
queryProvider.parseSyntax(this.ownerUri, this.commandTextBox.value).then(result => {
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) {
this.dialog.message = { text: this.FailureParseText };
}
@@ -246,7 +246,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
}).component();
this.typeDropdown.onValueChanged((type) => {
switch (type.selected) {
case (this.TSQLScript):
case(this.TSQLScript):
this.runAsDropdown.value = '';
this.runAsDropdown.values = [''];
this.runAsDropdown.enabled = false;
@@ -256,7 +256,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
this.processExitCodeBox.value = '';
this.processExitCodeBox.enabled = false;
break;
case (this.Powershell):
case(this.Powershell):
this.runAsDropdown.value = this.AgentServiceAccount;
this.runAsDropdown.values = [this.runAsDropdown.value];
this.runAsDropdown.enabled = true;
@@ -266,7 +266,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
this.processExitCodeBox.value = '';
this.processExitCodeBox.enabled = false;
break;
case (this.CmdExec):
case(this.CmdExec):
this.databaseDropdown.enabled = false;
this.databaseDropdown.values = [''];
this.databaseDropdown.value = '';
@@ -397,13 +397,13 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
let retryAttemptsContainer = view.modelBuilder.formContainer()
.withFormItems(
[{
component: this.retryAttemptsBox,
title: this.RetryAttemptsLabel
}], {
horizontal: false,
componentWidth: '100%'
})
[{
component: this.retryAttemptsBox,
title: this.RetryAttemptsLabel
}], {
horizontal: false,
componentWidth: '100%'
})
.component();
let retryIntervalContainer = view.modelBuilder.formContainer()
@@ -411,7 +411,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
[{
component: this.retryIntervalBox,
title: this.RetryIntervalLabel
}], {
}], {
horizontal: false
})
.component();
@@ -427,13 +427,13 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
let fileBrowserTitle = this.FileBrowserDialogTitle + `${this.server}`;
this.fileBrowserDialog = azdata.window.createModelViewDialog(fileBrowserTitle);
let fileBrowserTab = azdata.window.createTab('File Browser');
this.fileBrowserDialog.content = [fileBrowserTab];
this.fileBrowserDialog.content = [fileBrowserTab];
fileBrowserTab.registerContent(async (view) => {
this.fileBrowserTree = view.modelBuilder.fileBrowserTree()
.withProperties({ ownerUri: this.ownerUri, width: 420, height: 700 })
.component();
this.selectedPathTextBox = view.modelBuilder.inputBox()
.withProperties({ inputType: 'text' })
.withProperties({ inputType: 'text'})
.component();
this.fileBrowserTree.onDidChange((args) => {
this.selectedPathTextBox.value = args.fullPath;
@@ -462,7 +462,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
component: this.fileBrowserNameBox,
title: this.FileNameLabelString
}
]).component();
]).component();
view.initializeModel(fileBrowserContainer);
});
this.fileBrowserDialog.okButton.onClick(() => {

View File

@@ -135,7 +135,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
this.pagerTuesdayCheckBox.onChanged(() => {
if (this.pagerTuesdayCheckBox.checked) {
if (this.pagerTuesdayCheckBox .checked) {
this.weekdayPagerStartTimeInput.enabled = true;
this.weekdayPagerEndTimeInput.enabled = true;
} else {
@@ -153,7 +153,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
}).component();
this.pagerWednesdayCheckBox.onChanged(() => {
if (this.pagerWednesdayCheckBox.checked) {
if (this.pagerWednesdayCheckBox .checked) {
this.weekdayPagerStartTimeInput.enabled = true;
this.weekdayPagerEndTimeInput.enabled = true;
} else {
@@ -171,7 +171,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
}).component();
this.pagerThursdayCheckBox.onChanged(() => {
if (this.pagerThursdayCheckBox.checked) {
if (this.pagerThursdayCheckBox .checked) {
this.weekdayPagerStartTimeInput.enabled = true;
this.weekdayPagerEndTimeInput.enabled = true;
} else {
@@ -362,7 +362,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
}, {
component: pagerSundayCheckboxContainer,
title: ''
}],
}] ,
title: OperatorDialog.PagerDutyScheduleLabel
}]).withLayout({ width: '100%' }).component();
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.
*--------------------------------------------------------------------------------------------*/
'use strict';
'use strict';
import * as nls from 'vscode-nls';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
@@ -20,8 +20,8 @@ export class PickScheduleDialog {
private readonly CancelButtonText: string = localize('pickSchedule.cancel', 'Cancel');
private readonly SchedulesLabelText: string = localize('pickSchedule.availableSchedules', 'Available Schedules:');
public static readonly ScheduleNameLabelText: string = localize('pickSchedule.scheduleName', 'Name');
public static readonly SchedulesIDText: string = localize('pickSchedule.scheduleID', 'ID');
public static readonly ScheduleDescription: string = localize('pickSchedule.description', 'Description');
public static readonly SchedulesIDText: string = localize('pickSchedule.scheduleID','ID');
public static readonly ScheduleDescription: string = localize('pickSchedule.description','Description');
// UI Components
@@ -74,7 +74,7 @@ export class PickScheduleDialog {
let data: any[][] = [];
for (let i = 0; i < this.model.schedules.length; ++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;
}

View File

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

View File

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

View File

@@ -22,57 +22,57 @@ const localize = nls.loadMessageBundle();
* The main controller class that initializes the extension
*/
export class MainController {
protected _context: vscode.ExtensionContext;
protected _context: vscode.ExtensionContext;
// PUBLIC METHODS //////////////////////////////////////////////////////
public constructor(context: vscode.ExtensionContext) {
this._context = context;
}
// PUBLIC METHODS //////////////////////////////////////////////////////
public constructor(context: vscode.ExtensionContext) {
this._context = context;
}
public static showNotYetImplemented(): void {
vscode.window.showInformationMessage(
localize('mainController.notImplemented', "This feature is under development. Check-out the latest insiders build if you'd like to try out the most recent changes!"));
}
public static showNotYetImplemented(): void {
vscode.window.showInformationMessage(
localize('mainController.notImplemented', "This feature is under development. Check-out the latest insiders build if you'd like to try out the most recent changes!"));
}
/**
* Activates the extension
*/
public activate(): void {
vscode.commands.registerCommand('agent.openJobDialog', async (ownerUri: string, jobInfo: azdata.AgentJobInfo) => {
let dialog = new JobDialog(ownerUri, jobInfo);
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) => {
AgentUtils.getAgentService().then(async (agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new JobStepDialog(ownerUri, server, jobData, jobStepInfo, false);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
});
vscode.commands.registerCommand('agent.openPickScheduleDialog', async (ownerUri: string, jobName: string) => {
let dialog = new PickScheduleDialog(ownerUri, jobName);
await dialog.showDialog();
});
vscode.commands.registerCommand('agent.openAlertDialog', (ownerUri: string, jobInfo: azdata.AgentJobInfo, alertInfo: azdata.AgentAlertInfo) => {
AgentUtils.getAgentService().then(async (agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new AlertDialog(ownerUri, jobData, alertInfo, false);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
});
vscode.commands.registerCommand('agent.openOperatorDialog', async (ownerUri: string, operatorInfo: azdata.AgentOperatorInfo) => {
let dialog = new OperatorDialog(ownerUri, operatorInfo);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
vscode.commands.registerCommand('agent.openProxyDialog', async (ownerUri: string, proxyInfo: azdata.AgentProxyInfo, credentials: azdata.CredentialInfo[]) => {
let dialog = new ProxyDialog(ownerUri, proxyInfo, credentials);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
}
/**
* Activates the extension
*/
public activate(): void {
vscode.commands.registerCommand('agent.openJobDialog', async (ownerUri: string, jobInfo: azdata.AgentJobInfo) => {
let dialog = new JobDialog(ownerUri, jobInfo);
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) => {
AgentUtils.getAgentService().then(async(agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new JobStepDialog(ownerUri, server, jobData, jobStepInfo, false);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
});
vscode.commands.registerCommand('agent.openPickScheduleDialog', async (ownerUri: string, jobName: string) => {
let dialog = new PickScheduleDialog(ownerUri, jobName);
await dialog.showDialog();
});
vscode.commands.registerCommand('agent.openAlertDialog', (ownerUri: string, jobInfo: azdata.AgentJobInfo, alertInfo: azdata.AgentAlertInfo) => {
AgentUtils.getAgentService().then(async (agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new AlertDialog(ownerUri, jobData, alertInfo, false);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
});
vscode.commands.registerCommand('agent.openOperatorDialog', async (ownerUri: string, operatorInfo: azdata.AgentOperatorInfo) => {
let dialog = new OperatorDialog(ownerUri, operatorInfo);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
vscode.commands.registerCommand('agent.openProxyDialog', async (ownerUri: string, proxyInfo: azdata.AgentProxyInfo, credentials: azdata.CredentialInfo[]) => {
let dialog = new ProxyDialog(ownerUri, proxyInfo, credentials);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
}
/**
* Deactivates the extension
*/
public deactivate(): void {
}
/**
* Deactivates the extension
*/
public deactivate(): void {
}
}

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

@@ -1,18 +1,19 @@
{
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "./out",
"lib": [
"es6", "es2015.promise"
],
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "node"
},
"exclude": [
"node_modules"
]
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"declaration": true
},
"exclude": [
"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",
"icon": {
"light": "./resources/light/microsoft_account_light.svg",
"dark": "./resources/dark/microsoft_account_dark.svg"
"light": "./out/account-provider/media/microsoft_account_light.svg",
"dark": "./out/account-provider/media/microsoft_account_dark.svg"
}
},
{
"id": "work_school",
"icon": {
"light": "./resources/light/work_school_account_light.svg",
"dark": "./resources/dark/work_school_account_dark.svg"
"light": "./out/account-provider/media/work_school_account_light.svg",
"dark": "./out/account-provider/media/work_school_account_dark.svg"
}
}
],
@@ -104,8 +104,8 @@
"command": "azure.resource.connectsqldb",
"title": "%azure.resource.connectsqldb.title%",
"icon": {
"dark": "resources/dark/add_to_server_list_inverse.svg",
"light": "resources/light/add_to_server_list.svg"
"dark": "resources/dark/connect_to_inverse.svg",
"light": "resources/light/connect_to.svg"
}
}
],
@@ -156,19 +156,17 @@
"hasAzureResourceProviders": true
},
"dependencies": {
"adal-node": "^0.1.28",
"azure-arm-resource": "^7.0.0",
"azure-arm-sql": "^5.0.1",
"ms-rest": "^2.5.0",
"request": "2.88.0",
"vscode-nls": "^4.0.0"
},
"devDependencies": {
"@types/mocha": "^5.2.5",
"@types/node": "^10.12.12",
"@types/request": "^2.48.1",
"@types/node": "^8.0.24",
"mocha": "^5.2.0",
"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.signin.title": "Sign In",
"azure.resource.selectsubscriptions.title": "Select Subscriptions",
"azure.resource.connectsqlserver.title": "Connect",
"azure.resource.connectsqldb.title": "Add to Servers",
"azure.resource.connectsqlserver.title": "Add to Servers",
"azure.resource.connectsqldb.title": "Connect",
"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.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as adal from 'adal-node';
import * as azdata from 'azdata';
import * as request from 'request';
@@ -10,6 +12,7 @@ import * as nls from 'vscode-nls';
import * as vscode from 'vscode';
import * as url from 'url';
import {
Arguments,
AzureAccount,
AzureAccountProviderMetadata,
AzureAccountSecurityTokenCollection,
@@ -26,12 +29,17 @@ export class AzureAccountProvider implements azdata.AccountProvider {
private static AadCommonTenant: string = 'common';
// MEMBER VARIABLES ////////////////////////////////////////////////////
private _args: Arguments;
private _autoOAuthCancelled: boolean;
private _commonAuthorityUrl: string;
private _inProgressAutoOAuth: InProgressAutoOAuth;
private _isInitialized: boolean;
constructor(private _metadata: AzureAccountProviderMetadata, private _tokenCache: TokenCache) {
this._args = {
host: this._metadata.settings.host,
clientId: this._metadata.settings.clientId
};
this._autoOAuthCancelled = false;
this._inProgressAutoOAuth = null;
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
* @param accountKey Key identifying the account to delete tokens for
* @returns Promise to clear requested tokens from the token cache
* @param {"data".AccountKey} accountKey Key identifying the account to delete tokens for
* @returns {Thenable<void>} Promise to clear requested tokens from the token cache
*/
public clear(accountKey: azdata.AccountKey): Thenable<void> {
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.
* @returns Promise to clear the token cache
* @returns {Thenable<void>} Promise to clear the token cache
*/
public clearTokenCache(): Thenable<void> {
return this._tokenCache.clear();
@@ -84,13 +92,13 @@ export class AzureAccountProvider implements azdata.AccountProvider {
// NOTE: Based on ADAL implementation, getting tokens should use the refresh token if necessary
let task = this.getAccessTokens(account, azdata.AzureResource.ResourceManagement)
.then(
() => {
return account;
},
() => {
account.isStale = true;
return account;
}
() => {
return account;
},
() => {
account.isStale = true;
return account;
}
);
rehydrationTasks.push(task);
}
@@ -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
* 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.
* @param userId ID of the user to get a token for
* @param tenantId Tenant to get the token for
* @param resourceId ID of the resource the token will be good for
* @returns Promise to return a token. Rejected if retrieving the token fails.
* @param {string} userId ID of the user to get a token for
* @param {string} tenantId Tenant to get the token for
* @param {string} resourceId ID of the resource the token will be good for
* @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> {
let self = this;
@@ -338,9 +346,9 @@ export class AzureAccountProvider implements azdata.AccountProvider {
/**
* Performs a web request using the provided bearer token
* @param accessToken Bearer token for accessing the provided URI
* @param uri URI to access
* @returns Promise to return the deserialized body of the request. Rejected if error occurred.
* @param {TokenResponse} accessToken Bearer token for accessing the provided URI
* @param {string} uri URI to access
* @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> {
return new Promise<any>((resolve, reject) => {
@@ -355,7 +363,7 @@ export class AzureAccountProvider implements azdata.AccountProvider {
};
// 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) {
reject(error || JSON.stringify(body.error));
} else {
@@ -425,7 +433,6 @@ export class AzureAccountProvider implements azdata.AccountProvider {
name: tokenResponse.userId,
displayInfo: {
accountType: accountType,
userId: tokenResponse.userId,
contextualDisplayName: contextualDisplayName,
displayName: displayName
},

View File

@@ -77,14 +77,14 @@ export class AzureAccountProviderService implements vscode.Disposable {
return Promise.all(promises)
.then(
() => {
let message = localize('clearTokenCacheSuccess', 'Token cache successfully cleared');
vscode.window.showInformationMessage(`${constants.extensionName}: ${message}`);
},
err => {
let message = localize('clearTokenCacheFailure', 'Failed to clear token cache');
vscode.window.showErrorMessage(`${constants.extensionName}: ${message}: ${err}`);
});
() => {
let message = localize('clearTokenCacheSuccess', 'Token cache successfully cleared');
vscode.window.showInformationMessage(`${constants.extensionName}: ${message}`);
},
err => {
let message = localize('clearTokenCacheFailure', 'Failed to clear token cache');
vscode.window.showErrorMessage(`${constants.extensionName}: ${message}: ${err}`);
});
}
private onDidChangeConfiguration(): void {

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';
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.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as adal from 'adal-node';
import * as azdata from 'azdata';
import * as crypto from 'crypto';
@@ -32,8 +34,8 @@ export default class TokenCache implements adal.TokenCache {
.then(cache => self.addToCache(cache, entries))
.then(updatedCache => self.writeCache(updatedCache))
.then(
() => callback(null, false),
(err) => callback(err, true)
() => callback(null, false),
(err) => callback(err, true)
);
});
}
@@ -68,8 +70,8 @@ export default class TokenCache implements adal.TokenCache {
);
})
.then(
results => callback(null, results),
(err) => callback(err, null)
results => callback(null, results),
(err) => callback(err, null)
);
});
}
@@ -77,7 +79,7 @@ export default class TokenCache implements adal.TokenCache {
/**
* 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
* @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
*/
public findThenable(query: any): Thenable<any[]> {
@@ -102,16 +104,16 @@ export default class TokenCache implements adal.TokenCache {
.then(cache => self.removeFromCache(cache, entries))
.then(updatedCache => self.writeCache(updatedCache))
.then(
() => callback(null, null),
(err) => callback(err, null)
() => callback(null, null),
(err) => callback(err, null)
);
});
}
/**
* Wrapper to make callback-based remove method into a thenable method
* @param entries Array of entries to remove from the token cache
* @returns Promise to remove the given tokens from the token cache
* @param {TokenResponse[]} entries Array of entries to remove 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
*/
public removeThenable(entries: adal.TokenResponse[]): Thenable<void> {
@@ -136,7 +138,7 @@ export default class TokenCache implements adal.TokenCache {
&& 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) {
if (entry[key] === undefined || entry[key] !== query[key]) {
return false;
@@ -184,8 +186,8 @@ export default class TokenCache implements adal.TokenCache {
if (splitValues.length === 2 && splitValues[0] && splitValues[1]) {
try {
return <EncryptionParams>{
key: Buffer.from(splitValues[0], 'hex'),
initializationVector: Buffer.from(splitValues[1], 'hex')
key: new Buffer(splitValues[0], 'hex'),
initializationVector: new Buffer(splitValues[1], 'hex')
};
} catch (e) {
// 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.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import * as azdata from 'azdata';
@@ -13,6 +15,7 @@ import * as constants from './constants';
* this API from our code
*
* @export
* @class ApiWrapper
*/
export class ApiWrapper {
// Data APIs
@@ -153,6 +156,12 @@ export class ApiWrapper {
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> {
let options: vscode.TextDocumentShowOptions = {
viewColumn: column,
@@ -203,7 +212,7 @@ export class ApiWrapper {
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);
}

View File

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

View File

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

View File

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

View File

@@ -21,9 +21,9 @@ export class AzureResourceDatabaseServerService implements IAzureResourceDatabas
svrs.forEach((svr) => databaseServers.push({
name: svr.name,
fullName: svr.fullyQualifiedDomainName,
loginName: svr.administratorLogin,
defaultDatabaseName: 'master'
fullName: svr.fullyQualifiedDomainName,
loginName: svr.administratorLogin,
defaultDatabaseName: 'master'
}));
return databaseServers;

View File

@@ -5,7 +5,7 @@
'use strict';
import { ServiceClientCredentials } from 'ms-rest';
import { ServiceClientCredentials } from 'ms-rest';
import { azureResource } from '../../azure-resource';
import { AzureResourceDatabaseServer } from './models';

View File

@@ -17,10 +17,10 @@ export class AzureResourceCacheService implements IAzureResourceCacheService {
}
public generateKey(id: string): string {
return `${AzureResourceCacheService.cacheKeyPrefix}.${id}`;
}
return `${AzureResourceCacheService.cacheKeyPrefix}.${id}`;
}
public get<T>(key: string): T | undefined {
public get<T>(key: string): T | undefined {
return this._context.workspaceState.get(key);
}

View File

@@ -12,7 +12,7 @@ import { azureResource } from '../azure-resource';
import { IAzureResourceSubscriptionFilterService, IAzureResourceCacheService } from '../interfaces';
interface AzureResourceSelectedSubscriptionsCache {
selectedSubscriptions: { [accountId: string]: azureResource.AzureResourceSubscription[] };
selectedSubscriptions: { [accountId: string]: azureResource.AzureResourceSubscription[]};
}
export class AzureResourceSubscriptionFilterService implements IAzureResourceSubscriptionFilterService {
@@ -36,7 +36,7 @@ export class AzureResourceSubscriptionFilterService implements IAzureResourceSub
}
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);
if (cache) {

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