Compare commits
212 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
295004c42e | ||
|
|
45333e8852 | ||
|
|
e1280022d6 | ||
|
|
c90d630703 | ||
|
|
bfcdf28cbc | ||
|
|
1c694cbd3b | ||
|
|
2b0aba119d | ||
|
|
59cc8e5d7f | ||
|
|
f8da5bd1c7 | ||
|
|
26667eb1dc | ||
|
|
5e6a9ca9fa | ||
|
|
4ecf5fae84 | ||
|
|
f76500d5f0 | ||
|
|
2a212edf1e | ||
|
|
7bcd19987b | ||
|
|
0ce5f02dd2 | ||
|
|
0831e9e161 | ||
|
|
39f9c72390 | ||
|
|
0023714884 | ||
|
|
ec9fdc517f | ||
|
|
db387eb770 | ||
|
|
354ed22706 | ||
|
|
a69f194d8b | ||
|
|
f5d13319a2 | ||
|
|
9a0e691635 | ||
|
|
6c7cb185a1 | ||
|
|
ab22b93ce0 | ||
|
|
c7f5278430 | ||
|
|
56ad0dbaf2 | ||
|
|
74c92cd460 | ||
|
|
16ebb4322a | ||
|
|
fccd026812 | ||
|
|
b6e49f2bc0 | ||
|
|
188ccf849d | ||
|
|
1bfdce9642 | ||
|
|
495254b0be | ||
|
|
d209ff7b9a | ||
|
|
98eeb50060 | ||
|
|
8a68f0aaf9 | ||
|
|
039859213c | ||
|
|
a3c022aebf | ||
|
|
3a9b32b6e8 | ||
|
|
c1cb9000a9 | ||
|
|
104b99ffa0 | ||
|
|
a89d7f327a | ||
|
|
91bc4bde3c | ||
|
|
80da7ad496 | ||
|
|
64bf211a45 | ||
|
|
2558a66a48 | ||
|
|
df22eab4ec | ||
|
|
c2678cf818 | ||
|
|
f9af34b103 | ||
|
|
97cab22e00 | ||
|
|
64416e05c1 | ||
|
|
b21125ff2d | ||
|
|
e72d0d03ed | ||
|
|
0f12d15020 | ||
|
|
44a2d009c0 | ||
|
|
48682bacde | ||
|
|
f70369c2a6 | ||
|
|
f7fc94520a | ||
|
|
77c6f5c9a2 | ||
|
|
dffa47301b | ||
|
|
08f47e7e14 | ||
|
|
56342af140 | ||
|
|
aacc0eca67 | ||
|
|
02916aeffa | ||
|
|
e42bfada9d | ||
|
|
72fb114dec | ||
|
|
9ba1561386 | ||
|
|
39772c2dbe | ||
|
|
cbf3ca726f | ||
|
|
f1e21ebe9d | ||
|
|
49c36cc040 | ||
|
|
9b90400abd | ||
|
|
8cda364210 | ||
|
|
ca98ef879d | ||
|
|
bb9c85cd8f | ||
|
|
91b946bf3d | ||
|
|
64377000c6 | ||
|
|
23f4931a1d | ||
|
|
3625834028 | ||
|
|
705e7b30bc | ||
|
|
6528c0817d | ||
|
|
f3d7392af3 | ||
|
|
5d5f44ba11 | ||
|
|
34457880c7 | ||
|
|
d63f07d29a | ||
|
|
5c2cbc9d29 | ||
|
|
8dbfa10646 | ||
|
|
9e804089e0 | ||
|
|
51145903aa | ||
|
|
036c49f398 | ||
|
|
46b85ebc6b | ||
|
|
07bc5e2de9 | ||
|
|
e822091907 | ||
|
|
7d46e77922 | ||
|
|
ad528ad3d5 | ||
|
|
e8b4c03770 | ||
|
|
33aacc1798 | ||
|
|
58959ef35e | ||
|
|
c66b349cec | ||
|
|
5c90df092b | ||
|
|
32374f264f | ||
|
|
5e62229f25 | ||
|
|
1b24dff738 | ||
|
|
161135cd90 | ||
|
|
5fb583da06 | ||
|
|
8b40d20eab | ||
|
|
432034d2cb | ||
|
|
0e168e36fc | ||
|
|
f248260584 | ||
|
|
880e3e10da | ||
|
|
f33b95ee82 | ||
|
|
4a71eb9b90 | ||
|
|
3372a5ad4b | ||
|
|
8326f05f66 | ||
|
|
7ce921d449 | ||
|
|
31f7364f08 | ||
|
|
5119d28b9d | ||
|
|
a2a5fe3bee | ||
|
|
6222d8c977 | ||
|
|
d3699a261a | ||
|
|
9c0e56d640 | ||
|
|
ddd89fc52a | ||
|
|
b852f032d3 | ||
|
|
1fec26c6b3 | ||
|
|
d3483afaed | ||
|
|
910e4815fa | ||
|
|
ef118e3351 | ||
|
|
2beedb10d4 | ||
|
|
41bf10d989 | ||
|
|
ac3b6aef27 | ||
|
|
8956b591f7 | ||
|
|
2f8519cb6b | ||
|
|
15a19c044d | ||
|
|
ec47ff7479 | ||
|
|
82f707ee89 | ||
|
|
dfcab8db6a | ||
|
|
5c10127758 | ||
|
|
b376f36733 | ||
|
|
96c0f62cf5 | ||
|
|
a96f996b59 | ||
|
|
b75d0b6cb5 | ||
|
|
a5bc65fbfb | ||
|
|
dcdbc95ae7 | ||
|
|
72e7e5e025 | ||
|
|
57242a2e13 | ||
|
|
6dbf757385 | ||
|
|
c5a32d8373 | ||
|
|
34288435ec | ||
|
|
177b48c3f2 | ||
|
|
642f5d4405 | ||
|
|
92b1c59e48 | ||
|
|
cb1682542b | ||
|
|
9e56187c16 | ||
|
|
51851efda5 | ||
|
|
11e4b743e0 | ||
|
|
3349151d4c | ||
|
|
c8f6937166 | ||
|
|
ad36c1df3d | ||
|
|
a5b8924e2d | ||
|
|
bc898cc2c2 | ||
|
|
1247b6e8eb | ||
|
|
2111c3de1a | ||
|
|
bcea1b66be | ||
|
|
4f8d14ed3e | ||
|
|
442adfbbc3 | ||
|
|
fe12233954 | ||
|
|
c725f6f572 | ||
|
|
1870d83081 | ||
|
|
8315dacda4 | ||
|
|
18c54f41bd | ||
|
|
293f9c22c4 | ||
|
|
a74510544f | ||
|
|
9b053c50c2 | ||
|
|
88712f46bf | ||
|
|
d6df20b0e8 | ||
|
|
5dc37f7557 | ||
|
|
445d306586 | ||
|
|
d332ae1132 | ||
|
|
37f45b10a3 | ||
|
|
d9b6ec0654 | ||
|
|
f98428aea5 | ||
|
|
b3be1d79cd | ||
|
|
ea8f885f05 | ||
|
|
2de47c2a50 | ||
|
|
30b8e105f9 | ||
|
|
2a44fab8ba | ||
|
|
6a06a99e46 | ||
|
|
3670dfbebd | ||
|
|
daf929ecc7 | ||
|
|
f96a17c930 | ||
|
|
2fb06e7f4f | ||
|
|
4ece9b0085 | ||
|
|
a4bd31e96a | ||
|
|
8bdcc3267a | ||
|
|
9e9164c4ee | ||
|
|
5dc6a39652 | ||
|
|
ada0966832 | ||
|
|
e6faef27ab | ||
|
|
acc27d0829 | ||
|
|
ab54f7bb45 | ||
|
|
88161cc37d | ||
|
|
0975e6834e | ||
|
|
22ec1d5f0a | ||
|
|
01784dd186 | ||
|
|
02cf91c158 | ||
|
|
0532346f4f | ||
|
|
657adafb7d | ||
|
|
818c0789ea | ||
|
|
cb5bcf2248 |
6
.vscode/launch.json
vendored
@@ -70,10 +70,12 @@
|
||||
"timeout": 20000
|
||||
},
|
||||
"osx": {
|
||||
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh"
|
||||
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh",
|
||||
"timeout": 20000
|
||||
},
|
||||
"linux": {
|
||||
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh"
|
||||
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh",
|
||||
"timeout": 20000
|
||||
},
|
||||
"env": {
|
||||
"VSCODE_EXTHOST_WILL_SEND_SOCKET": null
|
||||
|
||||
14
.vscode/tasks.json
vendored
@@ -28,6 +28,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"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",
|
||||
|
||||
2
.yarnrc
@@ -1,3 +1,3 @@
|
||||
disturl "https://atom.io/download/electron"
|
||||
target "3.1.6"
|
||||
target "3.1.8"
|
||||
runtime "electron"
|
||||
|
||||
13
CHANGELOG.md
@@ -1,5 +1,18 @@
|
||||
# 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
|
||||
|
||||
15
README.md
@@ -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=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
|
||||
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
|
||||
|
||||
Go to our [download page](https://aka.ms/azuredatastudio) for more specific instructions.
|
||||
|
||||
@@ -68,6 +68,7 @@ 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`
|
||||
|
||||
@@ -24,21 +24,15 @@ steps:
|
||||
|
||||
- script: |
|
||||
yarn
|
||||
displayName: 'Install'
|
||||
displayName: 'Install'
|
||||
|
||||
- script: |
|
||||
node_modules/.bin/gulp electron
|
||||
node_modules/.bin/gulp compile --max_old_space_size=4096
|
||||
displayName: 'Scripts'
|
||||
yarn gulp electron-x64
|
||||
displayName: Download Electron
|
||||
|
||||
- script: |
|
||||
DISPLAY=:10 ./scripts/test.sh --reporter mocha-junit-reporter
|
||||
displayName: 'Tests'
|
||||
|
||||
- task: PublishTestResults@2
|
||||
inputs:
|
||||
testResultsFiles: '**/test-results.xml'
|
||||
condition: succeededOrFailed()
|
||||
yarn gulp hygiene
|
||||
displayName: Run Hygiene Checks
|
||||
|
||||
- script: |
|
||||
yarn tslint
|
||||
@@ -47,3 +41,29 @@ 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')
|
||||
|
||||
@@ -9,21 +9,12 @@ steps:
|
||||
displayName: 'Yarn Install'
|
||||
|
||||
- script: |
|
||||
.\node_modules\.bin\gulp electron
|
||||
yarn gulp electron-x64
|
||||
displayName: 'Electron'
|
||||
|
||||
- script: |
|
||||
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()
|
||||
yarn gulp hygiene
|
||||
displayName: Run Hygiene Checks
|
||||
|
||||
- script: |
|
||||
yarn tslint
|
||||
@@ -32,3 +23,22 @@ 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
|
||||
|
||||
@@ -65,8 +65,7 @@ interface Asset {
|
||||
platform: string;
|
||||
type: string;
|
||||
url: string;
|
||||
// {{SQL CARBON EDIT}}
|
||||
mooncakeUrl: string | undefined;
|
||||
mooncakeUrl?: string;
|
||||
hash: string;
|
||||
sha256hash: string;
|
||||
size: number;
|
||||
@@ -189,56 +188,18 @@ 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);
|
||||
|
||||
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) {
|
||||
if (blobExists) {
|
||||
console.log(`Blob ${quality}, ${blobName} already exists, not publishing again.`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Uploading blobs to Azure storage...');
|
||||
|
||||
await Promise.all(promises);
|
||||
await uploadBlob(blobService, quality, blobName, file);
|
||||
|
||||
console.log('Blobs successfully uploaded.');
|
||||
|
||||
@@ -250,8 +211,6 @@ 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
|
||||
|
||||
176
build/azure-pipelines/common/sync-mooncake.ts
Normal file
@@ -0,0 +1,176 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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();
|
||||
4
build/azure-pipelines/darwin/build.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
yarn gulp vscode-darwin-min
|
||||
yarn gulp upload-vscode-sourcemaps
|
||||
@@ -18,9 +18,15 @@ 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
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" yarn gulp -- mixin
|
||||
yarn gulp -- hygiene
|
||||
yarn gulp mixin
|
||||
yarn gulp hygiene
|
||||
yarn monaco-compile-check
|
||||
node build/azure-pipelines/common/installDistro.js
|
||||
node build/lib/builtInExtensions.js
|
||||
@@ -30,10 +36,7 @@ steps:
|
||||
set -e
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
|
||||
AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \
|
||||
yarn gulp -- vscode-darwin-min
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
|
||||
AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \
|
||||
yarn gulp -- upload-vscode-sourcemaps
|
||||
./build/azure-pipelines/darwin/build.sh
|
||||
displayName: Build
|
||||
|
||||
- script: |
|
||||
@@ -43,6 +46,11 @@ 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
|
||||
@@ -69,31 +77,12 @@ steps:
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
|
||||
# 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"`
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
|
||||
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)" \
|
||||
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
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||
VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \
|
||||
./build/azure-pipelines/darwin/publish.sh
|
||||
displayName: Publish
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
|
||||
22
build/azure-pipelines/darwin/publish.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/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
|
||||
30
build/azure-pipelines/distro-build.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
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
|
||||
3
build/azure-pipelines/linux/build.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
yarn gulp "vscode-linux-$VSCODE_ARCH-min"
|
||||
@@ -22,90 +22,45 @@ 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
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- mixin
|
||||
npm run gulp -- hygiene
|
||||
npm run monaco-compile-check
|
||||
yarn gulp mixin
|
||||
yarn gulp hygiene
|
||||
yarn 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)" npm run gulp -- vscode-linux-$(VSCODE_ARCH)-min
|
||||
name: build
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
|
||||
./build/azure-pipelines/linux/build.sh
|
||||
displayName: Build
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
npm run gulp -- "electron-$(VSCODE_ARCH)"
|
||||
yarn 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)"
|
||||
name: test
|
||||
displayName: Run unit tests
|
||||
|
||||
- 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)" \
|
||||
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)
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
|
||||
VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \
|
||||
./build/azure-pipelines/linux/publish.sh
|
||||
displayName: Publish
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
displayName: 'Component Detection'
|
||||
|
||||
51
build/azure-pipelines/linux/publish.sh
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/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)
|
||||
@@ -46,5 +46,4 @@ 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"
|
||||
@@ -62,4 +62,18 @@ jobs:
|
||||
pool:
|
||||
vmImage: macOS 10.13
|
||||
steps:
|
||||
- template: darwin/product-build-darwin.yml
|
||||
- template: darwin/product-build-darwin.yml
|
||||
|
||||
- job: Mooncake
|
||||
pool:
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
condition: true
|
||||
dependsOn:
|
||||
- Windows
|
||||
- Windows32
|
||||
- Linux
|
||||
- LinuxSnap
|
||||
- Linux32
|
||||
- macOS
|
||||
steps:
|
||||
- template: sync-mooncake.yml
|
||||
18
build/azure-pipelines/sync-mooncake.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
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"
|
||||
4
build/azure-pipelines/win32/build.ps1
Normal file
@@ -0,0 +1,4 @@
|
||||
. 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" }
|
||||
@@ -18,34 +18,47 @@ 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"
|
||||
$env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)"
|
||||
|
||||
exec { git config user.email "vscode@microsoft.com" }
|
||||
exec { git config user.name "VSCode" }
|
||||
exec { git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" }
|
||||
exec { git fetch distro }
|
||||
exec { git merge $(node -p "require('./package.json').distro") }
|
||||
|
||||
exec { yarn }
|
||||
exec { npm run gulp -- mixin }
|
||||
exec { npm run gulp -- hygiene }
|
||||
exec { npm run monaco-compile-check }
|
||||
exec { yarn gulp mixin }
|
||||
exec { yarn gulp hygiene }
|
||||
exec { yarn 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)"
|
||||
exec { npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-min" }
|
||||
exec { npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-inno-updater" }
|
||||
name: build
|
||||
.\build\azure-pipelines\win32\build.ps1
|
||||
displayName: Build
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm run gulp -- "electron-$(VSCODE_ARCH)" }
|
||||
exec { yarn gulp "electron-$(VSCODE_ARCH)" }
|
||||
exec { .\scripts\test.bat --build --tfs "Unit Tests" }
|
||||
# yarn smoketest -- --build "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)"
|
||||
name: test
|
||||
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
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||
inputs:
|
||||
ConnectedServiceName: 'ESRP CodeSign'
|
||||
FolderPath: '$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)'
|
||||
FolderPath: '$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH),$(agent.builddirectory)/vscode-reh-win32-$(VSCODE_ARCH)'
|
||||
Pattern: '*.dll,*.exe,*.node'
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: |
|
||||
@@ -119,32 +132,11 @@ 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)"
|
||||
|
||||
$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 }
|
||||
$env:VSCODE_HOCKEYAPP_TOKEN = "$(VSCODE_HOCKEYAPP_TOKEN)"
|
||||
.\build\azure-pipelines\win32\publish.ps1
|
||||
displayName: Publish
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
displayName: 'Component Detection'
|
||||
|
||||
28
build/azure-pipelines/win32/publish.ps1
Normal file
@@ -0,0 +1,28 @@
|
||||
. 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 }
|
||||
@@ -87,9 +87,16 @@ const indentationFilter = [
|
||||
'!build/azure-pipelines/**/*.js',
|
||||
'!build/azure-pipelines/**/*.config',
|
||||
'!**/Dockerfile',
|
||||
'!**/Dockerfile.*',
|
||||
'!**/*.Dockerfile',
|
||||
'!**/*.dockerfile',
|
||||
'!extensions/markdown-language-features/media/*.js'
|
||||
'!extensions/markdown-language-features/media/*.js',
|
||||
// {{SQL CARBON EDIT}}
|
||||
'!**/*.xlf',
|
||||
'!**/*.docx',
|
||||
'!**/*.sql',
|
||||
'!extensions/mssql/sqltoolsservice/**',
|
||||
'!extensions/import/flatfileimportservice/**',
|
||||
];
|
||||
|
||||
const copyrightFilter = [
|
||||
@@ -118,7 +125,37 @@ const copyrightFilter = [
|
||||
'!resources/completions/**',
|
||||
'!extensions/markdown-language-features/media/highlight.css',
|
||||
'!extensions/html-language-features/server/src/modes/typescript/*',
|
||||
'!extensions/*/server/bin/*'
|
||||
'!extensions/*/server/bin/*',
|
||||
// {{SQL CARBON EDIT}}
|
||||
'!extensions/notebook/src/intellisense/text.ts',
|
||||
'!extensions/mssql/src/objectExplorerNodeProvider/webhdfs.ts',
|
||||
'!src/sql/workbench/parts/notebook/outputs/tableRenderers.ts',
|
||||
'!src/sql/workbench/parts/notebook/outputs/common/url.ts',
|
||||
'!src/sql/workbench/parts/notebook/outputs/common/renderMimeInterfaces.ts',
|
||||
'!src/sql/workbench/parts/notebook/outputs/common/outputProcessor.ts',
|
||||
'!src/sql/workbench/parts/notebook/outputs/common/mimemodel.ts',
|
||||
'!src/sql/workbench/parts/notebook/cellViews/media/*.css',
|
||||
'!src/sql/base/browser/ui/table/plugins/rowSelectionModel.plugin.ts',
|
||||
'!src/sql/base/browser/ui/table/plugins/rowDetailView.ts',
|
||||
'!src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts',
|
||||
'!src/sql/base/browser/ui/table/plugins/checkboxSelectColumn.plugin.ts',
|
||||
'!src/sql/base/browser/ui/table/plugins/cellSelectionModel.plugin.ts',
|
||||
'!src/sql/base/browser/ui/table/plugins/autoSizeColumns.plugin.ts',
|
||||
'!src/sql/workbench/parts/notebook/outputs/sanitizer.ts',
|
||||
'!src/sql/workbench/parts/notebook/outputs/renderers.ts',
|
||||
'!src/sql/workbench/parts/notebook/outputs/registry.ts',
|
||||
'!src/sql/workbench/parts/notebook/outputs/factories.ts',
|
||||
'!src/sql/workbench/parts/notebook/models/nbformat.ts',
|
||||
'!extensions/markdown-language-features/media/tomorrow.css',
|
||||
'!src/sql/workbench/electron-browser/modelComponents/media/highlight.css',
|
||||
'!src/sql/parts/modelComponents/highlight.css',
|
||||
'!extensions/mssql/sqltoolsservice/**',
|
||||
'!extensions/import/flatfileimportservice/**',
|
||||
'!extensions/notebook/src/prompts/**',
|
||||
'!extensions/mssql/src/prompts/**',
|
||||
'!extensions/notebook/resources/jupyter_config/**',
|
||||
'!**/*.gif',
|
||||
'!**/*.xlf'
|
||||
];
|
||||
|
||||
const eslintFilter = [
|
||||
@@ -164,8 +201,7 @@ gulp.task('eslint', () => {
|
||||
});
|
||||
|
||||
gulp.task('tslint', () => {
|
||||
// {{SQL CARBON EDIT}}
|
||||
const options = { emitError: false };
|
||||
const options = { emitError: true };
|
||||
|
||||
return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
|
||||
.pipe(filter(tslintFilter))
|
||||
@@ -263,9 +299,8 @@ function hygiene(some) {
|
||||
.pipe(filter(f => !f.stat.isDirectory()))
|
||||
.pipe(filter(indentationFilter))
|
||||
.pipe(indentation)
|
||||
.pipe(filter(copyrightFilter));
|
||||
// {{SQL CARBON EDIT}}
|
||||
// .pipe(copyrights);
|
||||
.pipe(filter(copyrightFilter))
|
||||
.pipe(copyrights);
|
||||
|
||||
const typescript = result
|
||||
.pipe(filter(tslintFilter))
|
||||
@@ -275,15 +310,38 @@ function hygiene(some) {
|
||||
const javascript = result
|
||||
.pipe(filter(eslintFilter))
|
||||
.pipe(gulpeslint('src/.eslintrc'))
|
||||
.pipe(gulpeslint.formatEach('compact'));
|
||||
// {{SQL CARBON EDIT}}
|
||||
// .pipe(gulpeslint.failAfterError());
|
||||
.pipe(gulpeslint.formatEach('compact'))
|
||||
.pipe(gulpeslint.failAfterError());
|
||||
|
||||
let count = 0;
|
||||
return es.merge(typescript, javascript)
|
||||
.pipe(es.through(function (data) {
|
||||
// {{SQL CARBON EDIT}}
|
||||
this.emit('end');
|
||||
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');
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,21 +6,12 @@
|
||||
'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');
|
||||
|
||||
@@ -28,7 +28,6 @@ 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);
|
||||
|
||||
@@ -40,7 +39,7 @@ const formatFiles = (some) => {
|
||||
.pipe(filter(f => !f.stat.isDirectory()))
|
||||
.pipe(formatting);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
const formatStagedFiles = () => {
|
||||
const cp = require('child_process');
|
||||
@@ -81,4 +80,4 @@ const formatStagedFiles = () => {
|
||||
process.exit(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -33,12 +33,10 @@ 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));
|
||||
@@ -54,7 +52,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);
|
||||
@@ -77,14 +75,16 @@ 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}',
|
||||
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.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/electron-browser/webview-pre.js',
|
||||
'out-build/vs/workbench/contrib/webview/browser/pre/*.js',
|
||||
'out-build/vs/workbench/contrib/webview/electron-browser/pre/*.js',
|
||||
'out-build/vs/**/markdown.css',
|
||||
'out-build/vs/workbench/contrib/tasks/**/*.json',
|
||||
'out-build/vs/workbench/contrib/welcome/walkThrough/**/*.md',
|
||||
@@ -102,19 +102,17 @@ 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/parts/dashboard/**/*.html',
|
||||
'out-build/sql/workbench/parts/dashboard/**/*.html',
|
||||
'out-build/sql/parts/disasterRecovery/**/*.html',
|
||||
'out-build/sql/parts/common/modal/media/**',
|
||||
'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/workbench/parts/grid/media/**',
|
||||
'out-build/sql/workbench/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',
|
||||
'out-build/sql/media/objectTypes/*.svg',
|
||||
'out-build/sql/media/icons/*.svg',
|
||||
'out-build/sql/parts/notebook/media/**/*.svg',
|
||||
'out-build/sql/workbench/parts/notebook/media/**/*.svg',
|
||||
'!**/test/**'
|
||||
];
|
||||
|
||||
@@ -359,7 +357,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/**'], ['**/*.node', '**/*.a']))
|
||||
.pipe(util.cleanNodeModule('vscode-nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['build/Release/*.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']))
|
||||
@@ -426,14 +424,18 @@ 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)));
|
||||
}
|
||||
@@ -477,8 +479,6 @@ 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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 || {};
|
||||
|
||||
@@ -237,6 +237,7 @@ 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}}
|
||||
@@ -252,9 +253,10 @@ const sqlBuiltInExtensions = [
|
||||
'profiler',
|
||||
'admin-pack',
|
||||
'big-data-cluster',
|
||||
'dacpac'
|
||||
'dacpac',
|
||||
'schema-compare',
|
||||
'cms'
|
||||
];
|
||||
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
|
||||
@@ -290,8 +292,7 @@ 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 }) => azureExtensions.indexOf(name) === -1);
|
||||
.filter(({ name }) => sqlBuiltInExtensions.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}`));
|
||||
|
||||
@@ -283,6 +283,7 @@ interface IPackageExtensionsOptions {
|
||||
const excludedExtensions = [
|
||||
'vscode-api-tests',
|
||||
'vscode-colorize-tests',
|
||||
'vscode-test-resolver',
|
||||
'ms-vscode.node-debug',
|
||||
'ms-vscode.node-debug2',
|
||||
// {{SQL CARBON EDIT}}
|
||||
@@ -299,9 +300,10 @@ const sqlBuiltInExtensions = [
|
||||
'profiler',
|
||||
'admin-pack',
|
||||
'big-data-cluster',
|
||||
'dacpac'
|
||||
'dacpac',
|
||||
'schema-compare',
|
||||
'cms'
|
||||
];
|
||||
var azureExtensions = ['azurecore', 'mssql'];
|
||||
// {{SQL CARBON EDIT}} - End
|
||||
|
||||
interface IBuiltInExtension {
|
||||
@@ -350,8 +352,7 @@ 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 }) => azureExtensions.indexOf(name) === -1);
|
||||
.filter(({ name }) => sqlBuiltInExtensions.indexOf(name) === -1);
|
||||
|
||||
const localExtensions = () => sequence([...localExtensionDescriptions.map(extension => () => {
|
||||
return fromLocal(extension.path, opts.sourceMappingURLBase)
|
||||
|
||||
@@ -222,10 +222,6 @@
|
||||
"name": "vs/workbench/services/files",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/files2",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/integrity",
|
||||
"project": "vscode-workbench"
|
||||
|
||||
@@ -24,7 +24,7 @@ function log(message: any, ...rest: any[]): void {
|
||||
}
|
||||
|
||||
export interface Language {
|
||||
id: string; // laguage id, e.g. zh-tw, de
|
||||
id: string; // language 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';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 calback task
|
||||
// this is a callback task
|
||||
task((err) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
|
||||
@@ -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 calback task
|
||||
// this is a callback task
|
||||
task((err) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const ts = require("typescript");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as ts from 'typescript';
|
||||
|
||||
@@ -74,7 +74,7 @@ function update(options) {
|
||||
let translationPaths = [];
|
||||
i18n.pullI18nPackFiles(server, userName, apiToken, { id: languageId }, translationPaths)
|
||||
.on('error', (error) => {
|
||||
console.log(`Error occured while importing translations:`);
|
||||
console.log(`Error occurred 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 occured while importing translations:`);
|
||||
console.log(`Error occurred while importing translations:`);
|
||||
translationPaths = undefined;
|
||||
if (Array.isArray(error)) {
|
||||
error.forEach(console.log);
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"request": "^2.85.0",
|
||||
"tslint": "^5.9.1",
|
||||
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
|
||||
"typescript": "3.3.1",
|
||||
"typescript": "3.4.5",
|
||||
"vsce": "1.48.0",
|
||||
"xml2js": "^0.4.17"
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"resolveJsonModule": true,
|
||||
"experimentalDecorators": true,
|
||||
// enable JavaScript type checking for the language service
|
||||
// use the tsconfig.build.json for compiling wich disable JavaScript
|
||||
// use the tsconfig.build.json for compiling which disable JavaScript
|
||||
// type checking so that JavaScript file are not transpiled
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
@@ -22,4 +22,4 @@
|
||||
"exclude": [
|
||||
"node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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: checkedonce; Check: IsNotUpdate
|
||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked;
|
||||
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}"
|
||||
|
||||
@@ -3201,10 +3201,10 @@ typed-rest-client@^0.9.0:
|
||||
tunnel "0.0.4"
|
||||
underscore "1.8.3"
|
||||
|
||||
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==
|
||||
typescript@3.4.5:
|
||||
version "3.4.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99"
|
||||
integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==
|
||||
|
||||
uc.micro@^1.0.1, uc.micro@^1.0.5:
|
||||
version "1.0.5"
|
||||
|
||||
@@ -73,12 +73,12 @@
|
||||
"git": {
|
||||
"name": "electron",
|
||||
"repositoryUrl": "https://github.com/electron/electron",
|
||||
"commitHash": "73158a6419a3e2da9e4d523e1131052abd28fbbb"
|
||||
"commitHash": "e84a6860e35e14b4031b88bb9b49841cdb89a305"
|
||||
}
|
||||
},
|
||||
"isOnlyProductionDependency": true,
|
||||
"license": "MIT",
|
||||
"version": "3.1.6"
|
||||
"version": "3.1.8"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
@@ -111,11 +111,11 @@
|
||||
"git": {
|
||||
"name": "vscode-octicons-font",
|
||||
"repositoryUrl": "https://github.com/Microsoft/vscode-octicons-font",
|
||||
"commitHash": "5095860bb929919670646e2dfa0ee47d9b93bcb9"
|
||||
"commitHash": "4f69de3a233ed501c2098e33047e116ac2fbbf42"
|
||||
}
|
||||
},
|
||||
"license": "MIT",
|
||||
"version": "1.0.0"
|
||||
"version": "1.1.0"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
|
||||
@@ -1,61 +1,75 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
{
|
||||
"adminToolExtWin.launchSsmsServerPropertiesDialog": "Properties"
|
||||
"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..."
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
"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"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
* 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';
|
||||
@@ -11,15 +9,51 @@ import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { IConfig, ServerProvider } from 'service-downloader';
|
||||
import { Telemetry } from './telemetry';
|
||||
import * as utils from './utils';
|
||||
import { ChildProcess, exec, ExecException } from 'child_process';
|
||||
import { stringify } from 'querystring';
|
||||
import { doubleEscapeSingleQuotes, backEscapeDoubleQuotes, getConfiguration } from './utils';
|
||||
import { ChildProcess, exec } from 'child_process';
|
||||
|
||||
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 {
|
||||
@@ -27,7 +61,6 @@ export interface LaunchSsmsDialogParams {
|
||||
server: string;
|
||||
database?: string;
|
||||
user?: string;
|
||||
password?: string;
|
||||
useAad?: boolean;
|
||||
urn?: string;
|
||||
}
|
||||
@@ -39,8 +72,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 = utils.getConfiguration('http').get('proxy');
|
||||
config.strictSSL = utils.getConfiguration('http').get('proxyStrictSSL') || true;
|
||||
config.proxy = getConfiguration('http').get('proxy');
|
||||
config.strictSSL = getConfiguration('http').get('proxyStrictSSL') || true;
|
||||
|
||||
const serverdownloader = new ServerProvider(config);
|
||||
const installationStart = Date.now();
|
||||
@@ -55,9 +88,9 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
|
||||
} else {
|
||||
throw new Error('Could not find SsmsMin.exe after downloading');
|
||||
}
|
||||
// Add the command now that we have the exePath to run the tool with
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand('adminToolExtWin.launchSsmsServerPropertiesDialog', handleLaunchSsmsServerPropertiesDialogCommand));
|
||||
|
||||
// Register the commands now that we have the exePath to run the tool with
|
||||
registerCommands(context);
|
||||
|
||||
Telemetry.sendTelemetryEvent('startup/ExtensionStarted', {
|
||||
installationTime: String(installationComplete - installationStart),
|
||||
@@ -78,16 +111,56 @@ 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
|
||||
*/
|
||||
function handleLaunchSsmsServerPropertiesDialogCommand(connectionContext?: azdata.ObjectExplorerContext) {
|
||||
if (connectionContext && connectionContext.connectionProfile) {
|
||||
launchSsmsDialog(
|
||||
/*action*/'sqla:Properties@Microsoft.SqlServer.Management.Smo.Server',
|
||||
/*connectionProfile*/connectionContext.connectionProfile);
|
||||
async function handleLaunchSsmsMinPropertiesDialogCommand(connectionContext?: azdata.ObjectExplorerContext): Promise<void> {
|
||||
if (!connectionContext) {
|
||||
vscode.window.showErrorMessage(localize('adminToolExtWin.noConnectionContextForProp', 'No ConnectionContext provided for handleLaunchSsmsMinPropertiesDialogCommand'));
|
||||
return;
|
||||
}
|
||||
|
||||
let nodeType: string;
|
||||
if (connectionContext.isConnectionNode) {
|
||||
nodeType = 'Server';
|
||||
}
|
||||
else if (connectionContext.nodeInfo) {
|
||||
nodeType = connectionContext.nodeInfo.nodeType;
|
||||
}
|
||||
else {
|
||||
vscode.window.showErrorMessage(localize('adminToolExtWin.noOeNode', 'Could not determine NodeType for handleLaunchSsmsMinPropertiesDialogCommand with context {0}', JSON.stringify(connectionContext)));
|
||||
return;
|
||||
}
|
||||
|
||||
launchSsmsDialog(
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,29 +169,72 @@ function handleLaunchSsmsServerPropertiesDialogCommand(connectionContext?: azdat
|
||||
* @param params The params used to construct the command
|
||||
* @param urn The URN to pass to SsmsMin
|
||||
*/
|
||||
function launchSsmsDialog(action: string, connectionProfile: azdata.IConnectionProfile, urn?: string) {
|
||||
async function launchSsmsDialog(action: string, connectionContext: azdata.ObjectExplorerContext): Promise<void> {
|
||||
if (!exePath) {
|
||||
vscode.window.showErrorMessage(localize('adminToolExtWin.noExeError', 'Unable to find SsmsMin.exe.'));
|
||||
return;
|
||||
}
|
||||
|
||||
Telemetry.sendTelemetryEvent('LaunchSsmsDialog', { 'action': action });
|
||||
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];
|
||||
}
|
||||
|
||||
let params: LaunchSsmsDialogParams = {
|
||||
action: action,
|
||||
server: connectionProfile.serverName,
|
||||
database: connectionProfile.databaseName,
|
||||
password: connectionProfile.password,
|
||||
user: connectionProfile.userName,
|
||||
useAad: connectionProfile.authenticationType === 'AzureMFA',
|
||||
server: connectionContext.connectionProfile.serverName,
|
||||
database: connectionContext.connectionProfile.databaseName,
|
||||
user: connectionContext.connectionProfile.userName,
|
||||
useAad: connectionContext.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
|
||||
var proc: ChildProcess = exec(
|
||||
/*command*/`"${exePath}" ${args}`,
|
||||
/*options*/undefined,
|
||||
let 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);
|
||||
@@ -128,13 +244,15 @@ function launchSsmsDialog(action: string, connectionProfile: azdata.IConnectionP
|
||||
});
|
||||
let err = stderr.toString();
|
||||
if (err !== '') {
|
||||
console.warn(`Error calling SsmsMin with args '${args}' - ${err}`);
|
||||
vscode.window.showErrorMessage(localize(
|
||||
'adminToolExtWin.ssmsMinError',
|
||||
'Error calling SsmsMin with args \'{0}\' - {1}', args, err));
|
||||
}
|
||||
});
|
||||
|
||||
// If we're not using AAD the tool prompts for a password on stdin
|
||||
if (params.useAad !== true) {
|
||||
proc.stdin.end(params.password ? params.password : '');
|
||||
proc.stdin.end(password ? password : '');
|
||||
}
|
||||
|
||||
// Save the process into our map so we can make sure to stop them if we exit before shutting down
|
||||
@@ -148,10 +266,34 @@ function launchSsmsDialog(action: string, connectionProfile: azdata.IConnectionP
|
||||
* @param params The params used to build up the command parameter string
|
||||
*/
|
||||
export function buildSsmsMinCommandArgs(params: LaunchSsmsDialogParams): string {
|
||||
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, '\\"') + '"' : ''}\
|
||||
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) + '"' : ''}\
|
||||
${params.useAad === true ? ' -G' : ''}\
|
||||
${params.urn ? ' -u "' + params.urn.replace(/"/g, '\\"') + '"' : ''}`;
|
||||
${params.urn ? ' -u "' + backEscapeDoubleQuotes(params.urn) + '"' : ''}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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('/');
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
68
extensions/admin-tool-ext-win/src/test/stubs.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -8,60 +8,128 @@
|
||||
import * as should from 'should';
|
||||
import 'mocha';
|
||||
|
||||
import * as extensionMain from '../main';
|
||||
import { buildSsmsMinCommandArgs, buildUrn, LaunchSsmsDialogParams } from '../main';
|
||||
import { doubleEscapeSingleQuotes, backEscapeDoubleQuotes } from '../utils';
|
||||
import { ExtHostObjectExplorerNodeStub } from './stubs';
|
||||
|
||||
describe('buildSsmsMinCommandArgs Method Tests', () => {
|
||||
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 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 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 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 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 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 with only action and server', function (): void {
|
||||
it('Should be built correctly with only action and server', function (): void {
|
||||
|
||||
let params: extensionMain.LaunchSsmsDialogParams = {
|
||||
action: 'myAction',
|
||||
server: 'myServer'
|
||||
};
|
||||
let args = extensionMain.buildSsmsMinCommandArgs(params);
|
||||
should(args).equal('-a "myAction" -S "myServer"');
|
||||
});
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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,15 +28,33 @@ 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, '\\"');
|
||||
}
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
2710
extensions/agent/package-lock.json
generated
Normal file
@@ -2,14 +2,14 @@
|
||||
"name": "agent",
|
||||
"displayName": "SQL Server Agent",
|
||||
"description": "Manage and troubleshoot SQL Server Agent jobs",
|
||||
"version": "0.37.0",
|
||||
"version": "0.39.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": "0.10.x"
|
||||
"vscode": "^1.25.0"
|
||||
},
|
||||
"activationEvents": [
|
||||
"*"
|
||||
@@ -46,7 +46,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha-junit-reporter": "^1.17.0",
|
||||
"mocha-multi-reporters": "^1.1.7"
|
||||
"mocha-multi-reporters": "^1.1.7",
|
||||
"@types/mocha": "^5.2.5",
|
||||
"@types/node": "^8.10.25",
|
||||
"mocha": "^5.2.0",
|
||||
"should": "^13.2.1",
|
||||
"typemoq": "^2.1.0",
|
||||
"vscode": "1.1.5"
|
||||
},
|
||||
"__metadata": {
|
||||
"id": "10",
|
||||
|
||||
@@ -1,3 +1,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 azdata from 'azdata';
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* 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';
|
||||
|
||||
@@ -12,52 +11,51 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,22 +595,23 @@ 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;
|
||||
@@ -694,7 +695,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 = [];
|
||||
}
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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();
|
||||
});
|
||||
});
|
||||
82
extensions/agent/src/test/agentServiceTests/agent.test.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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);
|
||||
});
|
||||
});
|
||||
30
extensions/agent/src/test/index.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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;
|
||||
@@ -1,110 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 {
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
{
|
||||
"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",
|
||||
"declaration": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
"sourceMap": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node"
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
src/**
|
||||
out/**
|
||||
tsconfig.json
|
||||
extension.webpack.config.js
|
||||
yarn.lock
|
||||
|
||||
@@ -3,16 +3,19 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// localizable strings
|
||||
//@ts-check
|
||||
|
||||
export const InvalidProvider = 'Provider is invalid';
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Feature names
|
||||
*/
|
||||
export const RestoreFeatureName = 'restore';
|
||||
export const BackupFeatureName = 'backup';
|
||||
|
||||
export const MssqlProviderId = 'MSSQL';
|
||||
export const notebookModeId = 'notebook';
|
||||
const withDefaults = require('../shared.webpack.config');
|
||||
|
||||
module.exports = withDefaults({
|
||||
context: __dirname,
|
||||
entry: {
|
||||
extension: './src/extension.ts'
|
||||
},
|
||||
externals: {
|
||||
'ms-rest': 'commonjs ms-rest',
|
||||
'request': 'commonjs request'
|
||||
}
|
||||
});
|
||||
@@ -42,15 +42,15 @@
|
||||
{
|
||||
"id": "microsoft",
|
||||
"icon": {
|
||||
"light": "./out/account-provider/media/microsoft_account_light.svg",
|
||||
"dark": "./out/account-provider/media/microsoft_account_dark.svg"
|
||||
"light": "./resources/light/microsoft_account_light.svg",
|
||||
"dark": "./resources/dark/microsoft_account_dark.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "work_school",
|
||||
"icon": {
|
||||
"light": "./out/account-provider/media/work_school_account_light.svg",
|
||||
"dark": "./out/account-provider/media/work_school_account_dark.svg"
|
||||
"light": "./resources/light/work_school_account_light.svg",
|
||||
"dark": "./resources/dark/work_school_account_dark.svg"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -104,8 +104,8 @@
|
||||
"command": "azure.resource.connectsqldb",
|
||||
"title": "%azure.resource.connectsqldb.title%",
|
||||
"icon": {
|
||||
"dark": "resources/dark/connect_to_inverse.svg",
|
||||
"light": "resources/light/connect_to.svg"
|
||||
"dark": "resources/dark/add_to_server_list_inverse.svg",
|
||||
"light": "resources/light/add_to_server_list.svg"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -156,17 +156,19 @@
|
||||
"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": "^8.0.24",
|
||||
"@types/node": "^10.12.12",
|
||||
"@types/request": "^2.48.1",
|
||||
"mocha": "^5.2.0",
|
||||
"should": "^13.2.1",
|
||||
"typemoq": "^2.1.0",
|
||||
"vscode": "^1.1.26"
|
||||
"typemoq": "^2.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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": "Add to Servers",
|
||||
"azure.resource.connectsqldb.title": "Connect",
|
||||
"azure.resource.connectsqlserver.title": "Connect",
|
||||
"azure.resource.connectsqldb.title": "Add to Servers",
|
||||
|
||||
"accounts.clearTokenCache": "Clear Azure Account Token Cache",
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 226 B |
@@ -1 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 442 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,3 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 228 B |
@@ -1 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 400 B After Width: | Height: | Size: 400 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@@ -3,8 +3,6 @@
|
||||
* 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';
|
||||
@@ -12,7 +10,6 @@ import * as nls from 'vscode-nls';
|
||||
import * as vscode from 'vscode';
|
||||
import * as url from 'url';
|
||||
import {
|
||||
Arguments,
|
||||
AzureAccount,
|
||||
AzureAccountProviderMetadata,
|
||||
AzureAccountSecurityTokenCollection,
|
||||
@@ -29,17 +26,12 @@ 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;
|
||||
@@ -54,8 +46,8 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
||||
|
||||
/**
|
||||
* Clears all tokens that belong to the given account 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
|
||||
* @param accountKey Key identifying the account to delete tokens for
|
||||
* @returns Promise to clear requested tokens from the token cache
|
||||
*/
|
||||
public clear(accountKey: azdata.AccountKey): Thenable<void> {
|
||||
return this.doIfInitialized(() => this.clearAccountTokens(accountKey));
|
||||
@@ -63,7 +55,7 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
||||
|
||||
/**
|
||||
* Clears the entire token cache. Invoked by command palette action.
|
||||
* @returns {Thenable<void>} Promise to clear the token cache
|
||||
* @returns Promise to clear the token cache
|
||||
*/
|
||||
public clearTokenCache(): Thenable<void> {
|
||||
return this._tokenCache.clear();
|
||||
@@ -92,13 +84,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);
|
||||
}
|
||||
@@ -321,10 +313,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 {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.
|
||||
* @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.
|
||||
*/
|
||||
private getToken(userId: string, tenantId: string, resourceId: string): Thenable<adal.TokenResponse> {
|
||||
let self = this;
|
||||
@@ -346,9 +338,9 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
||||
|
||||
/**
|
||||
* Performs a web request using the provided bearer token
|
||||
* @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.
|
||||
* @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.
|
||||
*/
|
||||
private makeWebRequest(accessToken: adal.TokenResponse, uri: string): Thenable<any> {
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
@@ -363,7 +355,7 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
||||
};
|
||||
|
||||
// Setup the callback to resolve/reject this promise
|
||||
let callback = (error, response, body: { error: any; value: any; }) => {
|
||||
const callback: request.RequestCallback = (error, response, body: { error: any; value: any; }) => {
|
||||
if (error || body.error) {
|
||||
reject(error || JSON.stringify(body.error));
|
||||
} else {
|
||||
@@ -433,6 +425,7 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
||||
name: tokenResponse.userId,
|
||||
displayInfo: {
|
||||
accountType: accountType,
|
||||
userId: tokenResponse.userId,
|
||||
contextualDisplayName: contextualDisplayName,
|
||||
displayName: displayName
|
||||
},
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,3 +1,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 azdata from 'azdata';
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
* 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';
|
||||
@@ -34,8 +32,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)
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -70,8 +68,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)
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -79,7 +77,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 {Thenable<any[]>} Promise to return the matching adal.TokenResponse objects.
|
||||
* @returns Promise to return the matching adal.TokenResponse objects.
|
||||
* Rejected if an error was sent in the callback
|
||||
*/
|
||||
public findThenable(query: any): Thenable<any[]> {
|
||||
@@ -104,16 +102,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 {TokenResponse[]} entries Array of entries to remove from the token cache
|
||||
* @returns {Thenable<void>} Promise to remove the given tokens from the token cache
|
||||
* @param entries Array of entries to remove from the token cache
|
||||
* @returns 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> {
|
||||
@@ -138,7 +136,7 @@ export default class TokenCache implements adal.TokenCache {
|
||||
&& entry1.resource === entry2.resource;
|
||||
}
|
||||
|
||||
private static findByPartial(entry: adal.TokenResponse, query: object): boolean {
|
||||
private static findByPartial(entry: adal.TokenResponse, query: { [key: string]: any }): boolean {
|
||||
for (let key in query) {
|
||||
if (entry[key] === undefined || entry[key] !== query[key]) {
|
||||
return false;
|
||||
@@ -186,8 +184,8 @@ export default class TokenCache implements adal.TokenCache {
|
||||
if (splitValues.length === 2 && splitValues[0] && splitValues[1]) {
|
||||
try {
|
||||
return <EncryptionParams>{
|
||||
key: new Buffer(splitValues[0], 'hex'),
|
||||
initializationVector: new Buffer(splitValues[1], 'hex')
|
||||
key: Buffer.from(splitValues[0], 'hex'),
|
||||
initializationVector: Buffer.from(splitValues[1], 'hex')
|
||||
};
|
||||
} catch (e) {
|
||||
// Swallow the error and fall through to generate new params
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
* 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';
|
||||
|
||||
@@ -15,7 +13,6 @@ import * as constants from './constants';
|
||||
* this API from our code
|
||||
*
|
||||
* @export
|
||||
* @class ApiWrapper
|
||||
*/
|
||||
export class ApiWrapper {
|
||||
// Data APIs
|
||||
@@ -156,12 +153,6 @@ 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,
|
||||
@@ -212,7 +203,7 @@ export class ApiWrapper {
|
||||
return azdata.accounts.getAllAccounts();
|
||||
}
|
||||
|
||||
public getSecurityToken(account: azdata.Account, resource: azdata.AzureResource): Thenable<{}> {
|
||||
public getSecurityToken(account: azdata.Account, resource: azdata.AzureResource): Thenable<{ [key: string]: any }> {
|
||||
return azdata.accounts.getSecurityToken(account, resource);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
* 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';
|
||||
|
||||
|
||||
@@ -16,8 +16,7 @@ import { AzureResourceResourceTreeNode } from '../../resourceTreeNode';
|
||||
|
||||
export function registerAzureResourceDatabaseCommands(appContext: AppContext): void {
|
||||
appContext.apiWrapper.registerCommand('azure.resource.connectsqldb', async (node?: TreeNode) => {
|
||||
if (!node)
|
||||
{
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,7 @@ import { AzureResourceResourceTreeNode } from '../../resourceTreeNode';
|
||||
|
||||
export function registerAzureResourceDatabaseServerCommands(appContext: AppContext): void {
|
||||
appContext.apiWrapper.registerCommand('azure.resource.connectsqlserver', async (node?: TreeNode) => {
|
||||
if (!node)
|
||||
{
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||