Compare commits

...

212 Commits
1.6.0 ... 1.7.0

Author SHA1 Message Date
Alan Yu
295004c42e Adding CMS readme (#5417) 2019-05-07 17:59:15 -07:00
Alan Ren
45333e8852 bump the version of schema compare extension (#5411) 2019-05-07 17:59:06 -07:00
Aditya Bist
e1280022d6 Fix agent css in packaged builds (#5409)
* fix agent css in packaged

* fix agent css
2019-05-07 14:24:22 -07:00
Karl Burtram
c90d630703 Bump agent, import, profiler extension versions (#5405) 2019-05-07 13:03:28 -07:00
Karl Burtram
bfcdf28cbc Merge branch 'release/1.7' of https://github.com/Microsoft/azuredatastudio into release/1.7 2019-05-07 12:35:58 -07:00
Anthony Dresser
1c694cbd3b Fix css to fix new dashboard tab dialog (#5385)
* fix css to fix new dashboard tab dialog

* add readonly
2019-05-07 09:08:13 -07:00
kisantia
2b0aba119d bump dacpac extension version (#5387) 2019-05-07 09:08:04 -07:00
Karl Burtram
59cc8e5d7f Bump the VS Code version metadata (#5392) 2019-05-07 09:07:53 -07:00
Chris LaFreniere
f8da5bd1c7 Don't scroll when running code cell if in view (#5365) 2019-05-07 09:03:19 -07:00
Anthony Dresser
26667eb1dc Fix css to fix new dashboard tab dialog (#5385)
* fix css to fix new dashboard tab dialog

* add readonly
2019-05-06 17:33:26 -07:00
kisantia
5e6a9ca9fa bump dacpac extension version (#5387) 2019-05-06 17:33:19 -07:00
Karl Burtram
4ecf5fae84 Bump the VS Code version metadata (#5392) 2019-05-06 17:33:13 -07:00
Alan Ren
f76500d5f0 fix profiler formatter issue (#5372) 2019-05-06 15:58:55 -07:00
Maddy
2a212edf1e Maddy/newline overrides edit data (#5364)
* formatting it before displaying

* replace with space

* added comments and method to handle the line break space conversion
2019-05-06 15:58:47 -07:00
Anthony Dresser
7bcd19987b add a applystyle function with saftey checks in header filter (#5380) 2019-05-06 15:58:39 -07:00
Anthony Dresser
0ce5f02dd2 fix error icon (#5373) 2019-05-06 15:58:31 -07:00
udeeshagautam
0831e9e161 Changing the start for Schema compare and adding some text (#5356)
* Dialog Ok will not start Schema compare explit compare will. Adding wait text.

* Fixing variable name and spelling
2019-05-06 15:58:20 -07:00
Aditya Bist
39f9c72390 fixed packaged icons for azure (#5354) 2019-05-03 18:47:45 -07:00
Anthony Dresser
0023714884 Fix menu entry for tasks (#5355)
* fix menu entry for tasks

* change wording for action
2019-05-03 18:20:51 -07:00
kisantia
ec9fdc517f Fix schema compare dialog font sizes (#5353)
* make font sizes consistent

* fix order of source dialog options

* update fontsize to 13

* make fontsize a constant
2019-05-04 10:48:25 +12:00
Anthony Dresser
db387eb770 Fixing the layering in the base folder (#5308)
* removes more builder references

* remove builder from profiler

* formatting

* fix profiler dailog

* remove builder from oatuhdialog

* remove the rest of builder references

* formatting

* add more strict null checks to base

* enable strict tslint rules

* code layering of base

* wip

* working through changes to table data view

* fix tests

* update editabledropdown to not use layout service

* wip

* fix imports

* fix import

* fix compile error

* add more localization

* add comments to changes to import patterns

* add more import comments
2019-05-03 14:49:18 -07:00
kisantia
354ed22706 Fix #5314: schema compare doesn't always open with correct default connection (#5315)
* fix schema compare default connection when there are multiple connections
2019-05-04 09:40:53 +12:00
Aditya Bist
a69f194d8b Fixed CMS connection auth (#5306)
* fixed auth change to reflect in UI

* added comments

* fix bug where cms shows in dropdown

* added parameter to parent call
2019-05-03 13:26:04 -07:00
Aditya Bist
f5d13319a2 Remove CMS from packaged builds (#5349)
* remove cmss from packaged builds

* add repo to package file

* added cms to recommendations
2019-05-03 13:25:47 -07:00
Yurong He
9a0e691635 Change toolbar icon back to black (#5345)
* Change it back to black icon

* Install package icon
2019-05-03 13:11:44 -07:00
kisantia
6c7cb185a1 group source and target components into formcomponentgroups (#5329) 2019-05-04 05:51:40 +12:00
Charles Gagnon
ab22b93ce0 SsmsMin integration clean-up and improvements (#5339)
* SsmsMin integration clean-up and improvements

* Fix tests
2019-05-03 08:44:21 -07:00
Karl Burtram
c7f5278430 Remove 'Try backup or restore task' from task message (#5340) 2019-05-02 18:52:11 -07:00
Anthony Dresser
56ad0dbaf2 revert changes to common file and move icons to specific folder (#5335) 2019-05-02 18:14:13 -07:00
Anthony Dresser
74c92cd460 disable page scrolling in slickgrid (#5333) 2019-05-02 18:13:49 -07:00
Alan Ren
16ebb4322a fix insights dialog issue (#5336) 2019-05-02 18:13:33 -07:00
kisantia
fccd026812 Remove database name from schema compare source/target server field (#5327)
* remove database name from source/target server field
2019-05-03 11:20:28 +12:00
Charles Gagnon
b6e49f2bc0 Fix connections from editor not saving to MRU (#5328) 2019-05-02 16:08:46 -07:00
Karl Burtram
188ccf849d Fix nullref exception in connection profile (#5330)
* Fix nullref exception in connection profile

* Fix condition
2019-05-02 16:04:03 -07:00
Anthony Dresser
1bfdce9642 fix icons for various status; move menu entry to the other panels (#5319) 2019-05-02 14:31:58 -07:00
Karl Burtram
495254b0be Remove package-lock.json from extension sample (#5324) 2019-05-02 13:41:48 -07:00
Charles Gagnon
d209ff7b9a Fix broken CMS test and add to test-extensions-unit scripts (#5301) 2019-05-02 11:13:30 -07:00
Yurong He
98eeb50060 Fixed #4953 provider create file action when file is deleted (#5283)
* Fixed #4953 following query editor behavior provide create file option when file name doesn't exist

* Check active edtior is the correct one before closing

* close editor

* Removed codes not needed

* Check error null
2019-05-02 10:59:46 -07:00
Chris LaFreniere
8a68f0aaf9 Improvements to notebook editor code auto height (#5291) 2019-05-02 10:23:26 -07:00
Anthony Dresser
039859213c Replace observable references with just promises (#5278)
* replace observable references with just promises

* add tests for searching in dataview

* add comments

* work through respecting max matches

* fix tests

* fix strict null checks
2019-05-02 00:06:28 -07:00
Alan Ren
a3c022aebf Update dropdown.ts (#5290)
* Update dropdown.ts

fix the issue that the filtering feature is not working

* format the doc

* comments
2019-05-01 22:55:53 -07:00
Anthony Dresser
3a9b32b6e8 Task item look update (#5299)
* wip

* wip

* wip
2019-05-01 13:25:18 -07:00
Karl Burtram
c1cb9000a9 Various results grid scrolling fixes (#5285) 2019-05-01 12:36:16 -07:00
Kevin Cunnane
104b99ffa0 Fix #4553 Azure account prompt (#5303)
"Are you sure" prompt on removing Azure account does not respect "No"
2019-05-01 12:28:36 -07:00
Charles Gagnon
a89d7f327a Update SsmsMin to 15.0.18120.0 (#5293) 2019-05-01 11:29:36 -07:00
Charles Gagnon
91bc4bde3c Change default timeout value to 30sec to match SSMS (#5289) 2019-05-01 11:19:40 -07:00
Charles Gagnon
80da7ad496 Fix broken CMS commands (#5296) 2019-05-01 10:55:58 -07:00
Charles Gagnon
64bf211a45 Fix failing OE Tests caused by changes in connection API defaults (#5295)
* Fix failing OE Tests caused by changes in connection API defaults

* More spelling fixes
2019-05-01 10:18:23 -07:00
Anthony Dresser
2558a66a48 Merge from vscode 473af338e1bd9ad4d9853933da1cd9d5d9e07dc9 (#5286) 2019-04-30 21:53:52 -07:00
kisantia
df22eab4ec fix diff editor title disappearing after swap (#5280) 2019-05-01 11:30:03 +12:00
Aditya Bist
c2678cf818 Committer work - Agent tests (#5034)
* added couple tests

* added unit tests for agent extension

* added agent test in test script
2019-04-30 16:25:16 -07:00
Yurong He
f9af34b103 Notebook toolbar UI improvement (#5282)
Fixed  #5236
- Change the icon to blue image. Existing icons are not deleted. We will use them when the icons are - - moved as the secondary actions.
- Change the font size to 13px
- Change the height to 21px
- Move Add actions to the left
2019-04-30 16:18:48 -07:00
Charles Gagnon
97cab22e00 Add more SsmsMin interactions (#5267)
* Add support for more SsmsMin property dialogs and the Generate Script Wizard. Also fixed bug with ExtHostObjectExplorerNode getParent function

* Localize package.json entries

* Fix localization tokens

* Address PR comments

* Fix regex and getParent
2019-04-30 16:10:11 -07:00
Kevin Cunnane
64416e05c1 Notebook StdIn support to fix #5231 (#5232)
Fixes #5231 
- Add stdin handling. Has to be at UI level so add plumb through handling
- Add unit tests
- Add new StdIn component.

Testing:
Unit Tests and manual testing of following:
- Prompt for password using `getpass` in python.
   - Password prompt is hidden since "password" is true.
   - Hit enter, it completes
- prompt, stop cell running, StdIn disappears
- prompt, hit escape, stdIn disappears and stdIn request is handled.

Issues: focus isn't always set to the input even though we call focus.
Will investigate this further.
2019-04-30 14:57:27 -07:00
Kevin Cunnane
b21125ff2d Fix markdown security and enable most CSS (#5263)
* Fix markdown security and enable most CSS

Stops using our sanitizer and instead disables HTML in markdown engine
- This was blocking Note because it converted > to >
- It's slightly more strict in that it fully disables HTML unless trusted. Will need to improve handling of Trusted to support this in a future PR

Adds in correct CSS, both from .css file in markdown extension and from built-into all webviews global CSS
- Fix #3765 standard markdown support
- Fix Support of Notes by bringing correct styles
- Fix code block colorization
- Fix link handling so it's not bolded / gets underlined on hover
- Fixes table rendering (for markdown and HTML tables)

* Reduce scope of CSS changes
- Removed some CSS that wasn't needed or caused issues
- Scoped most things under the preview section not the whole component

* Avoid markdown html block by sanitizing after render

* Fix pre node not overflowing
- This was a bug in existing implementation too
2019-04-30 14:21:20 -07:00
Chris LaFreniere
e72d0d03ed Notebooks: More Jupyter Server Hardening (#5264)
* Do not rely on same starting port every time, misc

* put back to 5 seconds for process kill timeout

* extHostNotebook shutdown manager handle
2019-04-30 14:13:04 -07:00
Anthony Dresser
0f12d15020 Refactor connection store (#5024)
* various clean ups

* formatting

* remove linting

* formatting

* IConfigurationService is even better

* messing with connection config tests

* update tests

* formatting

* foramtting

* remove unused code

* add more tests

* working through tests

* formatting

* more factoring of connection store and increase code coverage

* formatting

* fix tests

* change use of state service to storage service

* remove unused files

* fix strict null errors

* formatting
2019-04-30 13:32:32 -07:00
Yurong He
44a2d009c0 Fixed #4169 shows notification when not active code cell is selected when hit F5 (#5259)
* Refine the msg
2019-04-30 13:25:11 -07:00
Anthony Dresser
48682bacde rework panel to not need platform (#5270) 2019-04-30 13:19:21 -07:00
Aditya Bist
f70369c2a6 Fix object explorer session fails (#5256)
* only start session if response successful

* added return type

* fixed OE tests

* format doc
2019-04-30 11:45:52 -07:00
udeeshagautam
f7fc94520a Fixing schema compare object type enum to follow PascalCasing (#5266) 2019-04-30 11:07:46 -07:00
udeeshagautam
77c6f5c9a2 Reverting the checkboxes because of scrollbar issue 5230 (#5271) 2019-04-30 11:07:11 -07:00
kisantia
dffa47301b fix path to dark icon of options button (#5274) 2019-05-01 05:53:55 +12:00
Charles Gagnon
08f47e7e14 Fix "Open File Location" for CSV Export (#5273)
Fix #5177 - File path wasn't being parsed correctly, URI.file should be used for full file paths.
2019-04-30 10:41:19 -07:00
Anthony Dresser
56342af140 Rework editableDropdown to not need platform (#5189)
* rework editableDropdown to not need platform

* rework editable dropdown to not depend on platform

* fix compile

* fix focus bluring
2019-04-30 09:25:04 -07:00
Anthony Dresser
aacc0eca67 Merge from vscode 071a5cf16fc999727acc31c790d78f750fa4b166 (#5261) 2019-04-30 07:54:56 -07:00
Kevin Cunnane
02916aeffa Fix #3440 link in Markdown requires cmd+click (#5239)
- Copied over click handler from VSCode markdown renderer
- Added logic to only support command links if trusted

Now clicking on a link will do an action or open a file.
Created #5238 to track need to support relative links which doesn't work
2019-04-29 19:15:39 -07:00
udeeshagautam
e42bfada9d Feature/schemacompare options (#5143)
* extension now working

* make button messages better

* fix diff editor title disappearing and remove border from source and target name boxes

* redoing a bunch of stuff that disappeared after rebasing

* add images and add to extensions.ts

* moving a few changes to the right place after rebase

* formatting

* Initial schema compare options working code

* Adding description.icon etc.

* Enabling disabling options button

* Name change: SchemaCompareOptions to DeploymentOptions. To reflect SqltoolsService side parameters

* Adding sorting and correct sql tools version

* Adding options button themes

* Formatting fix

* Adding get default options call to get options from tools service

* Exclude/Include changes - first commit

* Adding border to checkboxes

* Taking PR comments

* Updating to latest sqltools with schema compare options
2019-04-29 18:11:48 -07:00
Karl Burtram
72fb114dec Load MSSQL extension first during eager load phase (#5255) 2019-04-29 17:46:30 -07:00
Karl Burtram
9ba1561386 Bump SQL Tools Service to 1.5.0-alpha.91 (#5260) 2019-04-29 17:38:19 -07:00
Aditya Bist
39772c2dbe CMS Extension - 2 (#4908)
* first set of changes to experiment the registration of cms related apis

* Adding cms service entry to workbench

* Adding basic functionality for add remove reg servers and group

* Returning relative path as part of RegServerResult as string

* initial extension

* cleaned building with connecting to server

* get list of registered servers

* progress with registered servers tree

* cms base node with server selection

* removed unused services

* replaced azure stuff with cms

* removed cmsResourceService

* list servers progress

* Removing the cms apis from core. Having mssql extension expose them for cms extension

* create server working fine

* initial expansion and nodes

* Propogating the backend name changes to apis

* initial cms extension working

* cached connection needs change in api

* connect without dashboard in proposed

* Fixing some missing sqlops references

* add registered server bug found

* added refresh context menu option

* added payload

* server description not disabled after reject connection

* added more context actions and action icons

* added empty resource and error when same name server is added

* fixed connection issues with cms and normal connections

* added initial tests

* added cms icons

* removed azure readme

* test script revert

* fix build tests

* added more cms tests

* fixed test script

* fixed silent error when expanding servers

* added more cms tests

* removed cmsdialog from api

* cms dialog without object

* fixed theming issues

* initial connection dialog done

* can make connections

* PM asks for strings and icons

* removed search

* removed unused code and fixed 1 test

* fix connection management tests

* changed icons

* format file

* fixed hygiene

* initial cr comments

* refactored cms connection dialog

* fixed bug when switching dialogs

* localized connection provider options

* fixed cms provider name

* code review comments

* localized options in cms and mssql

* localized more options
2019-04-29 15:16:59 -07:00
David Shiflet
cbf3ca726f Connect opened query editors to the server (#5207)
* Connect opened query editors to the ser

* only show firewall rule error for one file

* remove unused imports

* sync to latest

* add comment

* one more comment
2019-04-29 13:10:19 -04:00
Yurong He
f1e21ebe9d Fix driverlog uri in output (#5212)
* Fixed #4813

* Changed to lowercase for comparision
2019-04-26 20:25:55 -07:00
Yurong He
49c36cc040 Fixed #4947 Increase the size of the notebook command icons and space between icon and button (#5235) 2019-04-26 19:57:40 -07:00
Anthony Dresser
9b90400abd Merge from vscode 63d257f78a36951ab7e821170ba675b11dc06d48 (#5240) 2019-04-26 17:24:54 -07:00
Karl Burtram
8cda364210 Fix product name in error message (#5233)
* Fix product name in error message

* fix typo
2019-04-26 15:32:30 -07:00
Anthony Dresser
ca98ef879d Last of the layering (#5187)
* layer query

* update imports
2019-04-26 15:30:41 -07:00
Chris LaFreniere
bb9c85cd8f Improve Cleanup of Jupyter processes on Notebook and/or ADS Close (#5142)
* Close jupyter and python

* Ensure we stop jupyter correctly on process end

* dont stopServer from clientSession shutdown

* PR comments

* close notebook after each test
2019-04-26 15:28:26 -07:00
Anthony Dresser
91b946bf3d rework listbox to not require platform (#5192) 2019-04-26 15:02:03 -07:00
kisantia
64377000c6 Change default folder in dacpac and schema compare extensions (#5215)
* change default folder in dacpac and schema compare extensions

* move getting rootpath to a method

* change method name
2019-04-27 04:27:03 +12:00
Yurong He
23f4931a1d Fixed #5210 (#5211)
* Fixed #5210

* Added function to check error to ensure get string
2019-04-25 19:45:33 -07:00
Anthony Dresser
3625834028 Merge from vscode 63655183ba5305b70ffaf1327b8a4708f0a79bd9 (#5221) 2019-04-25 19:18:04 -07:00
Alan Ren
705e7b30bc enable 'New Notebook' entry points for PG SQL (#5194)
* enable 'New Notebook' entry points for PG SQL

* fix comment

* permanent fix for context menu entry point
2019-04-25 16:23:01 -07:00
udeeshagautam
6528c0817d quick fix for column name (#5214) 2019-04-25 15:51:54 -07:00
Aditya Bist
f3d7392af3 Localize connection options for mssql (#5209)
* localize connection options for mssql

* added all strings
2019-04-25 15:13:07 -07:00
Yurong He
5d5f44ba11 Fixed #3961 Removed hardcoded value in notebook and use QueryEditor Result RowHight to keep it consistent (#5208) 2019-04-25 12:59:13 -07:00
Anthony Dresser
34457880c7 Merge from vscode 0fde6619172c9f04c41f2e816479e432cc974b8b (#5199) 2019-04-24 22:26:02 -07:00
kisantia
d63f07d29a Schema compare publish (#5127)
* adding publish command
2019-04-25 10:37:40 +12:00
Anthony Dresser
5c2cbc9d29 fix task contribution (#5188) 2019-04-24 15:05:11 -07:00
Karl Burtram
8dbfa10646 Bump npm packages (#5185) 2019-04-24 14:55:36 -07:00
Anthony Dresser
9e804089e0 Move Tasks Panel (#5162)
* moving tasks panel

* fix css styling

* clean up code

* do a bunch of renaming
2019-04-24 13:54:58 -07:00
v-mdriml
51145903aa LOC CHECKIN | Microsoft/azuredatastudio master | 20190424 (#5179) 2019-04-24 13:46:50 -07:00
Anthony Dresser
036c49f398 Modify coverage process to reduce time (#5164)
* modify coverage process to reduce time

* disable coverage on linux
2019-04-24 13:39:30 -07:00
Chris LaFreniere
46b85ebc6b Fix casing on welcome page to be consistent (#5169) 2019-04-24 11:18:33 -07:00
Yurong He
07bc5e2de9 Fixed #3244 (#5166) 2019-04-24 09:04:15 -07:00
Yurong He
e822091907 Only when the connection is connected, then do disconnect. (#5170) 2019-04-23 19:03:49 -07:00
Chris LaFreniere
7d46e77922 Notebooks: Show keyboard shortcut for run cell (#5097)
* Show keyboard shortcut for run cell

* PR comment
2019-04-23 17:33:15 -07:00
Karl Burtram
ad528ad3d5 Update Azure Data Studio to 1.7.0 for May release (#5167) 2019-04-23 17:24:24 -07:00
Yurong He
e8b4c03770 Fixed #4772 create unique connection for each notebook by using noteb… (#5163)
* Fixed #4772 create unique connection for each notebook by using notebook path as uri
Disconnect sqlConnection from SqlKernel to ensure no connection left after the notebook is closed.

* SqlSessionManager is ADS level manager

* Moved path to SqlKernel constructor
2019-04-23 16:42:28 -07:00
Chris LaFreniere
33aacc1798 Improve Notebook Context Menu Casing (#5145) 2019-04-23 11:35:46 -07:00
Anthony Dresser
58959ef35e Enable stricter compile options on extensions (#5044)
* enable stricter compile settings in extensions

* more strict compile

* formatting

* formatting

* revert some changes

* formtting

* formatting
2019-04-23 11:18:00 -07:00
Charles Gagnon
c66b349cec Show correct release notes for command (#5108) 2019-04-23 10:55:09 -07:00
Aditya Bist
5c90df092b Switch on code coverage (#5120)
* testing code coverage for /sql/

* fix test result path

* fixed coverage task:



'

* added coverage to linux and mac as well

* fix script for mac and linux

* bash script cmd

* fixed scripts

* remove warnings from summary

* remove coverage from linux

* added job action tests

* added more tests
2019-04-23 10:47:03 -07:00
Karl Burtram
32374f264f Adjust default fonts (#5146)
* Adjust default fonts

* Adjust default ratio
2019-04-22 17:30:16 -07:00
Anthony Dresser
5e62229f25 Merge from vscode 2b87545500dbc7899a493d69199aa4e061414ea0 (#5148) 2019-04-22 16:57:13 -07:00
Cory Rivera
1b24dff738 Show an Install Skipped message when Python already exists at the specified install location. (#5141)
* Also fixed a bug where future installs would get blocked after doing an install that gets skipped.
2019-04-22 14:28:59 -07:00
Aditya Bist
161135cd90 remove old unused splash screen (#5112) 2019-04-22 13:39:27 -07:00
Aditya Bist
5fb583da06 uncheck desktop icon by default (#5111) 2019-04-22 13:38:51 -07:00
Kevin Cunnane
8b40d20eab Typings reference failing in external extension (#5129)
This fixes an issue where if you copy azdata.proposed.d.ts to
an extension project, it would fail to compile using default
tsconfig.json settings due to missing return type
2019-04-19 16:41:23 -07:00
Chris LaFreniere
432034d2cb Notebooks: Pressing Escape key in markdown cell exits edit mode (#5094)
* Pressing Escape key in markdown exits edit mode

* text + code cells inactive when pressing escape
2019-04-19 16:19:16 -07:00
Alan Ren
0e168e36fc Merge from vscode 12cb89c82e88e035f4ab630f1b9fcebac338dc03 (#5125) 2019-04-19 10:26:20 -07:00
Cory Rivera
f248260584 Add flag to skip python install integration tests. (#5119) 2019-04-18 17:13:19 -07:00
Cory Rivera
880e3e10da Update Python install messages to differentiate between download completion and install completion. (#5114) 2019-04-18 16:52:50 -07:00
Anthony Dresser
f33b95ee82 Use vscode clipboard rather than clipboardy (#5117)
* remove clipboardy and use vscode's clipboard apis instead

* update lock
2019-04-18 16:34:24 -07:00
Anthony Dresser
4a71eb9b90 use vscode open external rather than opener (#5115) 2019-04-18 16:34:12 -07:00
Chris LaFreniere
3372a5ad4b Fix hygiene issues in textCell.css (#5116) 2019-04-18 15:58:27 -07:00
Zbyněk Sailer
8326f05f66 LOC CHECKIN | Microsoft/azuredatastudio master | 20190418 (#5103) 2019-04-18 14:59:25 -07:00
Chris LaFreniere
7ce921d449 Improve tabe markdown css (#5093) 2019-04-18 14:57:26 -07:00
Chris LaFreniere
31f7364f08 Only show nb loading spinner when no cells shown (#5095) 2019-04-18 14:57:11 -07:00
Anthony Dresser
5119d28b9d fix svg references (#5109) 2019-04-18 12:29:18 -07:00
Yurong He
a2a5fe3bee Added more logging for python installation and remove dup test in the other suite (#5106) 2019-04-18 11:24:12 -07:00
Karl Burtram
6222d8c977 Bump agent extension to 0.38.0 (#5104) 2019-04-18 09:48:47 -07:00
Karl Burtram
d3699a261a Update readme for April release (#5063) 2019-04-18 09:25:01 -07:00
Anthony Dresser
9c0e56d640 Layering of everything else but query (#5085)
* layer profiler and edit data

* relayering everything but query

* fix css import

* readd qp

* fix script src

* fix hygiene
2019-04-18 01:28:43 -07:00
Anthony Dresser
ddd89fc52a Renable Strict TSLint (#5018)
* removes more builder references

* remove builder from profiler

* formatting

* fix profiler dailog

* remove builder from oatuhdialog

* remove the rest of builder references

* formatting

* add more strict null checks to base

* enable strict tslint rules

* fix formatting

* fix compile error

* fix the rest of the hygeny issues and add pipeline step

* fix pipeline files
2019-04-18 00:34:53 -07:00
Alan Ren
b852f032d3 Merge from vscode 3a6dcb42008d509900b3a3b2d695564eeb4dbdac (#5098) 2019-04-17 23:38:44 -07:00
Aditya Bist
1fec26c6b3 dont dispose serverTreeView every time hidden (#5092) 2019-04-17 20:12:44 -07:00
kisantia
d3483afaed Schema Compare extension (#4974)
* extension now working

* fix diff editor title disappearing and remove border from source and target name boxes

* redoing a bunch of stuff that disappeared after rebasing

* add images and add to extensions.ts

* moving a few changes to the right place after rebase

* formatting

* update toolbar svgs

* addressing comments

* add return types

* Adding PR comments

* Adding light and dark theme icons

* Fixing the diff editor title for dark theme
2019-04-17 19:14:22 -07:00
Chris LaFreniere
910e4815fa Enable Python Integration Tests For Notebooks (#5090)
* Enable python notebook tests

* change run_python3_test to be string

* Add explicit pyspark check
2019-04-17 16:46:10 -07:00
Karl Burtram
ef118e3351 Update extension recommendation list (#5086) 2019-04-17 16:26:41 -07:00
Chris LaFreniere
2beedb10d4 Add run cells as a command (#5080) 2019-04-17 14:26:31 -07:00
Charles Gagnon
41bf10d989 Fix for build break caused by missing SVG (#5078)
* Fix for build break caused by missing SVG

These files were moved in #5029

* Add a few more missing SVGs
2019-04-17 11:22:42 -07:00
Chris LaFreniere
ac3b6aef27 ADS Welcome Page (#5043)
* ADS Welcome Page

* sample notebook section

* Opens in browser :(

* Remove sample notebooks section

* fix open file in windows

* Change az_data_welcome_page to be under sql/

* fix tslint issue

* Scope table css down
2019-04-17 10:50:43 -07:00
Anthony Dresser
8956b591f7 Merge from vscode 05fc61ffb1aee9fd19173c32113daed079f9b7bd (#5074)
* Merge from vscode 05fc61ffb1aee9fd19173c32113daed079f9b7bd

* fix tests
2019-04-16 22:11:30 -07:00
Anthony Dresser
2f8519cb6b Layer Object Explorer; query plan; task history (#5030)
* relayer query plan, task history, object-explorer

* formatting
2019-04-16 21:12:34 -07:00
Aditya Bist
15a19c044d remove agent from old apis (#5064) 2019-04-16 17:13:02 -07:00
Alan Ren
ec47ff7479 Alanren/fixsmoketest (#5019)
* fix the smoke test

* update readme

* fix the selector for server name input

* add new property to server profile engineType
2019-04-16 16:43:11 -07:00
Aditya Bist
82f707ee89 Fixed agent filter in dark theme (#5048)
* fixed agent filter in dark theme

* added high contrast theme as well
2019-04-16 15:30:16 -07:00
Alan Ren
dfcab8db6a fix the selectbox issue for chart (#5052) 2019-04-16 13:32:52 -07:00
Anthony Dresser
5c10127758 Layer grid code (#5029)
* layer grid

* errors; edit data still not showing up

* fix edit data

* fix tab spaces
2019-04-16 13:30:15 -07:00
Aditya Bist
b376f36733 fix job action context (#5053) 2019-04-16 13:07:22 -07:00
Aditya Bist
96c0f62cf5 Removed duplicate connections code (#5045)
* removed duplicate connections code

* removed old comment

* removed unused code
2019-04-16 11:54:07 -07:00
Zbyněk Sailer
a96f996b59 LOC CHECKIN | Microsoft/azuredatastudio master | 20190411 (#4993) 2019-04-16 10:36:41 -07:00
Anthony Dresser
b75d0b6cb5 Fix bootstrapping around dashboard (#5040) 2019-04-15 23:49:40 -07:00
Anthony Dresser
a5bc65fbfb Merge from vscode 8b5ebbb1b8f6b2127bbbd551ac10cc080482d5b4 (#5041) 2019-04-15 20:37:22 -07:00
Gene Lee
dcdbc95ae7 Fixed bug: CheckboxTreeNode label overflows, and node icon disappears (#5022) 2019-04-15 13:44:49 -07:00
Anthony Dresser
72e7e5e025 relayer connection code; formatting (#5020) 2019-04-15 01:05:23 -07:00
Anthony Dresser
57242a2e13 Merge from vscode 3d67364fbfcf676d93be64f949e9b33e7f1b969e (#5028) 2019-04-14 22:29:14 -07:00
Anthony Dresser
6dbf757385 Remove some vscode differences (#5010)
* remove some vscode differences

* add dates to todo comments
2019-04-12 21:55:07 -07:00
Karl Burtram
c5a32d8373 Show user email address in account picker (#5015)
* Show user email address in account picker

* Fix build break and remove Azure account from sqlops namespace
2019-04-12 17:23:48 -07:00
Charles Gagnon
34288435ec Fix Data Explorer context menu items visibility (#4996)
* Fix Data Explorer context menu items visibility

The when clause was making the menu items show up for all nodes in the Data Explorer - even ones that didn't make sense such as the Databases folders. This change makes it only appear for the Database and Server nodes (which is how the OE tree is set up)
2019-04-12 17:09:53 -07:00
Yurong He
177b48c3f2 Revert #4955 to unblock integration test (#5016) 2019-04-12 14:08:38 -07:00
Anthony Dresser
642f5d4405 replace nulls with undefined (#5014) 2019-04-12 13:08:32 -07:00
Anthony Dresser
92b1c59e48 Strict null check on full "base" code (#4973)
* removes more builder references

* remove builder from profiler

* formatting

* fix profiler dailog

* remove builder from oatuhdialog

* remove the rest of builder references

* formatting

* add more strict null checks to base
2019-04-12 12:59:58 -07:00
Anthony Dresser
cb1682542b remove sql/services (#4991) 2019-04-12 12:48:06 -07:00
Anthony Dresser
9e56187c16 Remove sql/common (#4990)
* remove sql/common/

* formatting

* fix cyclic dependency
2019-04-12 12:47:48 -07:00
Yurong He
51851efda5 Use notebookUtils.getErrorMessage to get the correct msg instead of showing {0} (#5012) 2019-04-12 11:50:44 -07:00
Charles Gagnon
11e4b743e0 Fix wrong release notes being loaded (#5008) 2019-04-11 16:56:55 -07:00
Kevin Cunnane
3349151d4c Touchbar icon support in notebooks (#4998)
* Touchbar icon support in notebooks
- updated shortcut keys to only work if notebook is active
- Added icons
- Now have 1 "add cell" icon that prompts for code/text.
This is useful as there wasn't an icon to differentiate
2019-04-11 16:43:27 -07:00
Kevin Cunnane
c8f6937166 Fix #4500 Untitled notebook reopen doesn't show dirty (#5005)
* Fix 2 notebook issues
- Do not create notebook model twice on start
- Do not cause disposed warnings due to markdown cell deserialization

* Fix notebook dirty on open issue
Before model is resolved we weren't getting dirty events.
Solution is to use backing text model until it's ready.
Must hook to the dirty event & notify to get the dot to appear
2019-04-11 16:39:54 -07:00
Maddy
ad36c1df3d add wrap to the <pre> tag (#5002)
* add wrap to the <pre> tag

* removed styles for browser support
2019-04-11 15:32:52 -07:00
Anthony Dresser
a5b8924e2d restore line height to account list renderer (#4999) 2019-04-11 15:10:38 -07:00
Anthony Dresser
bc898cc2c2 revert data explorer id to connections (#5003) 2019-04-11 15:10:26 -07:00
kisantia
1247b6e8eb bump SQL Tools to 1.5.0-alpha.85 to get invalid dacpac version fix (#5001) 2019-04-11 13:53:45 -07:00
udeeshagautam
2111c3de1a Fix for 4104 : Multiple consecutive spaces in query results cells are condensed into one (#4983)
* preserving spaces in query results - all beginning, trailing and middle spaces will be shown as is

* removing the change through formatting and replacing with css change formatting was leaving special char while removing nbsp
2019-04-11 13:45:10 -07:00
Aditya Bist
bcea1b66be Added some usage details (#4711)
* added some details

* remove unused import

* added new metrics, removed churn

* merged master and code review comments

* code review comments

* normalized days to calendar days/weeks/months

* cleaned up code

* changed comment to start required check for PR

* fix failing test

* fix test

* removed null assignment

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

* Moved toggleUserSelect into ngOnChanges

* Resolve PR comments
2019-04-11 11:36:42 -07:00
Chris LaFreniere
442adfbbc3 Add New Notebook from Server Dashboard (#4971) 2019-04-11 10:15:45 -07:00
Aditya Bist
fe12233954 Azure extension changes (#4987)
* removed search box

* removed commented code
2019-04-11 09:44:43 -07:00
Anthony Dresser
c725f6f572 fix html structure of add account dialog (#4988) 2019-04-10 17:41:18 -07:00
Cory Rivera
1870d83081 Add additional error handling to Python installation for Notebooks (#4891)
* Also enabled integration tests for python installation.
2019-04-10 17:09:28 -07:00
Anthony Dresser
8315dacda4 Merge from vscode 31e03b8ffbb218a87e3941f2b63a249f061fe0e4 (#4986) 2019-04-10 16:29:23 -07:00
kisantia
18c54f41bd remove unnecessary message that connection is needed (#4982) 2019-04-10 16:22:18 -07:00
Kevin Cunnane
293f9c22c4 Touchbar support for Run Cell, Run Query, Add Cell (#4972)
* Basic touchbar support

* Touchbar support for Run Cell, Run Query, Add Cell
- Add top 3 notebook commands
- Add top query command

Actions only appear on having active editor of expected type.
In order to make Notebook work as expected, added tabindex to support focusing
and hide outline to ensure it doesn't get weird blue outline on click
Note: does not have icons yet, which would be nice.
However can add in subsequent PR once this comes from UX.
2019-04-10 14:04:36 -07:00
Anthony Dresser
a74510544f Remove rest of builder (#4963)
* removes more builder references

* remove builder from profiler

* formatting

* fix profiler dailog

* remove builder from oatuhdialog

* remove the rest of builder references

* formatting
2019-04-10 13:23:33 -07:00
Aditya Bist
9b053c50c2 Azure - icon change (#4967)
* changed icon and string

* changed add to servers icon
2019-04-10 13:20:43 -07:00
Chris LaFreniere
88712f46bf Fix for relative markdown image paths (#4889)
* Fix for relative markdown image paths

* PR comments
2019-04-10 11:35:06 -07:00
Chris LaFreniere
d6df20b0e8 Notebooks: Potential Fix for "Notebook Provider does not Exist" Error (#4848)
* Fallback to SQL

* Fix providers not found issue

* await whenInstalledExtensionsRegistered

* PR comments
2019-04-10 11:34:46 -07:00
Chris LaFreniere
5dc37f7557 improve assert message (#4968) 2019-04-10 10:14:44 -07:00
Gene Lee
445d306586 Fixed Broken Notebook Preview (#4895) 2019-04-09 18:47:24 -07:00
Chris LaFreniere
d332ae1132 Fix to ensure that we rewrite spark ui links correctly (#4962) 2019-04-09 18:23:21 -07:00
Kevin Cunnane
37f45b10a3 Mitigate (but not fully fix) Run Cell from disconnected notebook (#4960)
This is a partial fix that lays groundwork for full "Prompt to connect" if a kernel needs a connection.
I am waiting on Yurong's refactoring of connection handling before doing any of the prompt work.

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

In the future, this path will still be used if user is prompted to connect and cancels out.
The future change will be to inject a "connect" handler from notebook.component to the cell callback and use to set connection context
2019-04-09 17:45:05 -07:00
kisantia
d9b6ec0654 Add title for DiffEditor and fix SplitViewContainer (#4961)
* add option to have diff editor title

* fix component being undefined and splitter not showing
2019-04-09 16:41:32 -07:00
kisantia
f98428aea5 Add reverse color option to text diff editor (#4826)
* Add reverse color option to text diff editor
2019-04-09 16:26:41 -07:00
Gene Lee
b3be1d79cd Add support for new endpoint key string 'gateway' (#4954) 2019-04-09 15:19:02 -07:00
Yurong He
ea8f885f05 Call getCurrentGlobalConnection like New Query to get the active connection context (#4955) 2019-04-09 15:15:36 -07:00
Kevin Cunnane
2de47c2a50 Fix #4930 Text cells are referred to as text and markdown in commands (#4956) 2019-04-09 14:20:29 -07:00
Kevin Cunnane
30b8e105f9 Fix #4893 New Notebook Can Open Existing Noteboon (#4959)
Add back check for textDocuments with same name, should've been there anyhow

On rehydration files show as text docs before clicking as only get
changed by customInputConverter code path.
We should look at this long term - ideally we'd update notebookDocuments
with correct values on initial start. #4958 opened to track this.
2019-04-09 14:11:10 -07:00
Kevin Cunnane
2a44fab8ba Fix issue where mac launch often failed to attach (#4957)
- Timeout now matches the windows timeout value
2019-04-09 14:10:56 -07:00
Chris LaFreniere
6a06a99e46 Change pfs.rimraf call in insightsutils test (#4921) 2019-04-09 13:05:36 -07:00
Anthony Dresser
3670dfbebd changes strings for data explorer (#4946) 2019-04-09 12:39:15 -07:00
kisantia
daf929ecc7 add splitViewContainer and diffEditor to ModelBuilder interface (#4950) 2019-04-09 11:45:21 -07:00
Anthony Dresser
f96a17c930 Remove unused code (#4873)
* removes unused features

* remove more unused code; formatting

* lock changes

* fix run issue
2019-04-09 02:00:51 -07:00
Anthony Dresser
2fb06e7f4f Move notebooks to workbench (#4888)
* move notebooks under workbench

* fix style imports
2019-04-09 01:59:55 -07:00
Anthony Dresser
4ece9b0085 remove dispose of button listeners (#4914) 2019-04-09 01:08:56 -07:00
Anthony Dresser
a4bd31e96a Removes Builder references from modal (#4869)
* remove builder from modal

* add more DOM methods
2019-04-09 00:28:52 -07:00
Anthony Dresser
8bdcc3267a Code Layering dashboard (#4883)
* move dashboard to workbench

* revert xlf file changes

* 💄

* 💄

* add back removed functions
2019-04-09 00:26:57 -07:00
Takahito Yamatoya
9e9164c4ee fix the format (#4899) 2019-04-08 19:56:44 -07:00
Alan Ren
5dc6a39652 Update readme.md (#4907) 2019-04-08 16:25:53 -07:00
kisantia
ada0966832 Add toolbar separator (#4890)
* Add option to add toolbar separator after toolbar component
2019-04-08 15:27:18 -07:00
Alan Ren
e6faef27ab Alanren/integration setup (#4871)
* automate the setup and use akv to store values

* update readme.md

* get rid of the save to file part

* update readme

* add more messages

* fix the error

* fix some errors

* fix the readme
2019-04-08 15:11:38 -07:00
Anthony Dresser
acc27d0829 Code Layering Accounts (#4882)
* code layering for accounts

* formatting

* formatting

* formatting
2019-04-08 14:45:30 -07:00
Anthony Dresser
ab54f7bb45 remove builder references from some componnets (#4868) 2019-04-08 14:24:03 -07:00
Yurong He
88161cc37d Fixed cancel connectionDialog from attach to shows dup "select connection" (#4865) 2019-04-08 14:06:46 -07:00
Anthony Dresser
0975e6834e remove builder from taskswidget (#4866) 2019-04-08 13:28:23 -07:00
Anthony Dresser
22ec1d5f0a Strict Null Checks, Builder Removal, Formatting (#4849)
* remove builder; more null checks

* null checks

* formatting

* wip

* fix dropdown themeing

* formatting

* formatting

* fix tests

* update what files are checked

* add code to help refresh bad nodes
2019-04-08 13:27:41 -07:00
udeeshagautam
01784dd186 Adding Diff view and Split view container as Model View Editor Components (#4831)
* intial code for diff view inside model view

* Adding basic Split View Container depending on Flex Layout

* Enabled resizing between top and bottom view

* cleaning up some of the sqlops references

* Adding height as per CR comment
2019-04-08 11:11:14 -07:00
Karl Burtram
02cf91c158 Remove broken VS Code test from merge (#4887) 2019-04-05 15:06:11 -07:00
Karl Burtram
0532346f4f Merge from vscode 591842cc4b71958c81947b254924a215fe3edcbd (#4886) 2019-04-05 14:14:26 -07:00
Chris LaFreniere
657adafb7d always serialize execution count (#4864) 2019-04-05 11:34:10 -07:00
Anthony Dresser
818c0789ea Reduce packaged size of extensions (#4300)
* reduce output of notebooks

* reduce size of azurecore

* update mssql extensions to be webpacked

* formatting

* remove commented code

* fix packaged config

* fix mssql packing
2019-04-05 10:48:00 -07:00
Karl Burtram
cb5bcf2248 Merge from vscode 2b0b9136329c181a9e381463a1f7dc3a2d105a34 (#4880) 2019-04-05 10:09:18 -07:00
2157 changed files with 123450 additions and 84508 deletions

6
.vscode/launch.json vendored
View File

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

14
.vscode/tasks.json vendored
View File

@@ -28,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", "type": "gulp",
"task": "tslint", "task": "tslint",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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();

View File

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

View File

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

View File

@@ -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

View 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

View File

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

View File

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

View File

@@ -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)

View File

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

View File

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

View File

@@ -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"

View 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" }

View File

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

View File

@@ -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 }

View File

@@ -87,9 +87,16 @@ const indentationFilter = [
'!build/azure-pipelines/**/*.js', '!build/azure-pipelines/**/*.js',
'!build/azure-pipelines/**/*.config', '!build/azure-pipelines/**/*.config',
'!**/Dockerfile', '!**/Dockerfile',
'!**/Dockerfile.*',
'!**/*.Dockerfile', '!**/*.Dockerfile',
'!**/*.dockerfile', '!**/*.dockerfile',
'!extensions/markdown-language-features/media/*.js' '!extensions/markdown-language-features/media/*.js',
// {{SQL CARBON EDIT}}
'!**/*.xlf',
'!**/*.docx',
'!**/*.sql',
'!extensions/mssql/sqltoolsservice/**',
'!extensions/import/flatfileimportservice/**',
]; ];
const copyrightFilter = [ const copyrightFilter = [
@@ -118,7 +125,37 @@ const copyrightFilter = [
'!resources/completions/**', '!resources/completions/**',
'!extensions/markdown-language-features/media/highlight.css', '!extensions/markdown-language-features/media/highlight.css',
'!extensions/html-language-features/server/src/modes/typescript/*', '!extensions/html-language-features/server/src/modes/typescript/*',
'!extensions/*/server/bin/*' '!extensions/*/server/bin/*',
// {{SQL CARBON EDIT}}
'!extensions/notebook/src/intellisense/text.ts',
'!extensions/mssql/src/objectExplorerNodeProvider/webhdfs.ts',
'!src/sql/workbench/parts/notebook/outputs/tableRenderers.ts',
'!src/sql/workbench/parts/notebook/outputs/common/url.ts',
'!src/sql/workbench/parts/notebook/outputs/common/renderMimeInterfaces.ts',
'!src/sql/workbench/parts/notebook/outputs/common/outputProcessor.ts',
'!src/sql/workbench/parts/notebook/outputs/common/mimemodel.ts',
'!src/sql/workbench/parts/notebook/cellViews/media/*.css',
'!src/sql/base/browser/ui/table/plugins/rowSelectionModel.plugin.ts',
'!src/sql/base/browser/ui/table/plugins/rowDetailView.ts',
'!src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts',
'!src/sql/base/browser/ui/table/plugins/checkboxSelectColumn.plugin.ts',
'!src/sql/base/browser/ui/table/plugins/cellSelectionModel.plugin.ts',
'!src/sql/base/browser/ui/table/plugins/autoSizeColumns.plugin.ts',
'!src/sql/workbench/parts/notebook/outputs/sanitizer.ts',
'!src/sql/workbench/parts/notebook/outputs/renderers.ts',
'!src/sql/workbench/parts/notebook/outputs/registry.ts',
'!src/sql/workbench/parts/notebook/outputs/factories.ts',
'!src/sql/workbench/parts/notebook/models/nbformat.ts',
'!extensions/markdown-language-features/media/tomorrow.css',
'!src/sql/workbench/electron-browser/modelComponents/media/highlight.css',
'!src/sql/parts/modelComponents/highlight.css',
'!extensions/mssql/sqltoolsservice/**',
'!extensions/import/flatfileimportservice/**',
'!extensions/notebook/src/prompts/**',
'!extensions/mssql/src/prompts/**',
'!extensions/notebook/resources/jupyter_config/**',
'!**/*.gif',
'!**/*.xlf'
]; ];
const eslintFilter = [ const eslintFilter = [
@@ -164,8 +201,7 @@ gulp.task('eslint', () => {
}); });
gulp.task('tslint', () => { gulp.task('tslint', () => {
// {{SQL CARBON EDIT}} const options = { emitError: true };
const options = { emitError: false };
return vfs.src(all, { base: '.', follow: true, allowEmpty: true }) return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
.pipe(filter(tslintFilter)) .pipe(filter(tslintFilter))
@@ -263,9 +299,8 @@ function hygiene(some) {
.pipe(filter(f => !f.stat.isDirectory())) .pipe(filter(f => !f.stat.isDirectory()))
.pipe(filter(indentationFilter)) .pipe(filter(indentationFilter))
.pipe(indentation) .pipe(indentation)
.pipe(filter(copyrightFilter)); .pipe(filter(copyrightFilter))
// {{SQL CARBON EDIT}} .pipe(copyrights);
// .pipe(copyrights);
const typescript = result const typescript = result
.pipe(filter(tslintFilter)) .pipe(filter(tslintFilter))
@@ -275,15 +310,38 @@ function hygiene(some) {
const javascript = result const javascript = result
.pipe(filter(eslintFilter)) .pipe(filter(eslintFilter))
.pipe(gulpeslint('src/.eslintrc')) .pipe(gulpeslint('src/.eslintrc'))
.pipe(gulpeslint.formatEach('compact')); .pipe(gulpeslint.formatEach('compact'))
// {{SQL CARBON EDIT}} .pipe(gulpeslint.failAfterError());
// .pipe(gulpeslint.failAfterError());
let count = 0; let count = 0;
return es.merge(typescript, javascript) return es.merge(typescript, javascript)
.pipe(es.through(function (data) { .pipe(es.through(function (data) {
// {{SQL CARBON EDIT}} count++;
this.emit('end'); 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');
}
})); }));
} }

View File

@@ -6,21 +6,12 @@
'use strict'; 'use strict';
const gulp = require('gulp'); const gulp = require('gulp');
const json = require('gulp-json-editor');
const buffer = require('gulp-buffer');
const filter = require('gulp-filter');
const es = require('event-stream');
const vfs = require('vinyl-fs');
const pkg = require('../package.json');
const cp = require('child_process');
const fancyLog = require('fancy-log');
const ansiColors = require('ansi-colors');
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
const jeditor = require('gulp-json-editor'); const jeditor = require('gulp-json-editor');
gulp.task('mixin', function () { gulp.task('mixin', function () {
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
const updateUrl = process.env['SQLOPS_UPDATEURL']; const updateUrl = process.env['SQLOPS_UPDATEURL'];
if (!updateUrl) { if (!updateUrl) {
console.log('Missing SQLOPS_UPDATEURL, skipping mixin'); console.log('Missing SQLOPS_UPDATEURL, skipping mixin');

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
"use strict"; "use strict";
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the 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 }); Object.defineProperty(exports, "__esModule", { value: true });
const ts = require("typescript"); const ts = require("typescript");

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the 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'; import * as ts from 'typescript';

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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..."
} }

View File

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

View File

@@ -2,8 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
///
'use strict';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import * as path from 'path'; import * as path from 'path';
@@ -11,15 +9,51 @@ import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { IConfig, ServerProvider } from 'service-downloader'; import { IConfig, ServerProvider } from 'service-downloader';
import { Telemetry } from './telemetry'; import { Telemetry } from './telemetry';
import * as utils from './utils'; import { doubleEscapeSingleQuotes, backEscapeDoubleQuotes, getConfiguration } from './utils';
import { ChildProcess, exec, ExecException } from 'child_process'; import { ChildProcess, exec } from 'child_process';
import { stringify } from 'querystring';
const baseConfig = require('./config.json'); const baseConfig = require('./config.json');
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
let exePath: string; let exePath: string;
let runningProcesses: Map<number, ChildProcess> = new Map<number, ChildProcess>(); let runningProcesses: Map<number, ChildProcess> = new Map<number, ChildProcess>();
interface SmoMapping {
action: string;
urnName: string;
}
const nodeTypeToUrnNameMapping: { [oeNodeType: string]: SmoMapping } = {
'Database': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Database', urnName: 'Database' },
'Server': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Server', urnName: 'Server' },
'ServerLevelServerAudit': { action: 'sqla:AuditProperties', urnName: 'Audit' },
'ServerLevelCredential': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Credential', urnName: 'Credential' },
'ServerLevelServerRole': { action: 'sqla:ManageServerRole', urnName: 'Role' },
'ServerLevelServerAuditSpecification': { action: 'sqla:ServerAuditSpecificationProperties', urnName: 'ServerAuditSpecification' },
'ServerLevelLinkedServer': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.LinkedServer', urnName: 'LinkedServer' },
'Table': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Table', urnName: 'Table' },
'View': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.View', urnName: 'View' },
'Column': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Column', urnName: 'Column' },
'Index': { action: 'sqla:IndexProperties', urnName: 'Index' },
'Statistic': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Statistic', urnName: 'Statistic' },
'StoredProcedure': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.StoredProcedure', urnName: 'StoredProcedure' },
'ScalarValuedFunction': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.UserDefinedFunction', urnName: 'UserDefinedFunction' },
'TableValuedFunction': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.UserDefinedFunction', urnName: 'UserDefinedFunction' },
'AggregateFunction': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.UserDefinedFunction', urnName: 'UserDefinedFunction' },
'Synonym': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Synonym', urnName: 'Synonym' },
'Assembly': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.SqlAssembly', urnName: 'SqlAssembly' },
'UserDefinedDataType': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.UserDefinedDataType', urnName: 'UserDefinedDataType' },
'UserDefinedType': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.UserDefinedType', urnName: 'UserDefinedType' },
'UserDefinedTableType': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.UserDefinedTableType', urnName: 'UserDefinedTableType' },
'Sequence': { action: 'sqla:SequenceProperties', urnName: 'Sequence' },
'User': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.User', urnName: 'User' },
'DatabaseRole': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.DatabaseRole', urnName: 'Role' },
'ApplicationRole': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.ApplicationRole', urnName: 'ApplicationRole' },
'Schema': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Schema', urnName: 'Schema' },
'SecurityPolicy': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.SecurityPolicy', urnName: 'SecurityPolicy' },
'ServerLevelLogin': { action: 'sqla:Properties@Microsoft.SqlServer.Management.Smo.Login', urnName: 'Login' },
};
// Params to pass to SsmsMin.exe, only an action and server are required - the rest are optional based on the // Params to pass to SsmsMin.exe, only an action and server are required - the rest are optional based on the
// action used. Exported for use in testing. // action used. Exported for use in testing.
export interface LaunchSsmsDialogParams { export interface LaunchSsmsDialogParams {
@@ -27,7 +61,6 @@ export interface LaunchSsmsDialogParams {
server: string; server: string;
database?: string; database?: string;
user?: string; user?: string;
password?: string;
useAad?: boolean; useAad?: boolean;
urn?: string; urn?: string;
} }
@@ -39,8 +72,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
let config: IConfig = JSON.parse(JSON.stringify(baseConfig)); let config: IConfig = JSON.parse(JSON.stringify(baseConfig));
config.installDirectory = path.join(context.extensionPath, config.installDirectory); config.installDirectory = path.join(context.extensionPath, config.installDirectory);
config.proxy = utils.getConfiguration('http').get('proxy'); config.proxy = getConfiguration('http').get('proxy');
config.strictSSL = utils.getConfiguration('http').get('proxyStrictSSL') || true; config.strictSSL = getConfiguration('http').get('proxyStrictSSL') || true;
const serverdownloader = new ServerProvider(config); const serverdownloader = new ServerProvider(config);
const installationStart = Date.now(); const installationStart = Date.now();
@@ -55,9 +88,9 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
} else { } else {
throw new Error('Could not find SsmsMin.exe after downloading'); throw new Error('Could not find SsmsMin.exe after downloading');
} }
// Add the command now that we have the exePath to run the tool with
context.subscriptions.push( // Register the commands now that we have the exePath to run the tool with
vscode.commands.registerCommand('adminToolExtWin.launchSsmsServerPropertiesDialog', handleLaunchSsmsServerPropertiesDialogCommand)); registerCommands(context);
Telemetry.sendTelemetryEvent('startup/ExtensionStarted', { Telemetry.sendTelemetryEvent('startup/ExtensionStarted', {
installationTime: String(installationComplete - installationStart), installationTime: String(installationComplete - installationStart),
@@ -78,16 +111,56 @@ export async function deactivate(): Promise<void> {
runningProcesses.forEach(p => exec('taskkill /pid ' + p.pid + ' /T /F')); runningProcesses.forEach(p => exec('taskkill /pid ' + p.pid + ' /T /F'));
} }
/**
* Registers extension commands with command subsystem
* @param context The context used to register the commands
*/
function registerCommands(context: vscode.ExtensionContext): void {
context.subscriptions.push(
vscode.commands.registerCommand('adminToolExtWin.launchSsmsMinPropertiesDialog', handleLaunchSsmsMinPropertiesDialogCommand));
context.subscriptions.push(
vscode.commands.registerCommand('adminToolExtWin.launchSsmsMinGswDialog', handleLaunchSsmsMinGswDialogCommand));
}
/** /**
* Handler for command to launch SSMS Server Properties dialog * Handler for command to launch SSMS Server Properties dialog
* @param connectionId The connection context from the command * @param connectionId The connection context from the command
*/ */
function handleLaunchSsmsServerPropertiesDialogCommand(connectionContext?: azdata.ObjectExplorerContext) { async function handleLaunchSsmsMinPropertiesDialogCommand(connectionContext?: azdata.ObjectExplorerContext): Promise<void> {
if (connectionContext && connectionContext.connectionProfile) { if (!connectionContext) {
launchSsmsDialog( vscode.window.showErrorMessage(localize('adminToolExtWin.noConnectionContextForProp', 'No ConnectionContext provided for handleLaunchSsmsMinPropertiesDialogCommand'));
/*action*/'sqla:Properties@Microsoft.SqlServer.Management.Smo.Server', return;
/*connectionProfile*/connectionContext.connectionProfile);
} }
let nodeType: string;
if (connectionContext.isConnectionNode) {
nodeType = 'Server';
}
else if (connectionContext.nodeInfo) {
nodeType = connectionContext.nodeInfo.nodeType;
}
else {
vscode.window.showErrorMessage(localize('adminToolExtWin.noOeNode', 'Could not determine NodeType for handleLaunchSsmsMinPropertiesDialogCommand with context {0}', JSON.stringify(connectionContext)));
return;
}
launchSsmsDialog(
nodeTypeToUrnNameMapping[nodeType].action,
connectionContext);
}
/**
* Handler for command to launch SSMS "Generate Script Wizard" dialog
* @param connectionId The connection context from the command
*/
async function handleLaunchSsmsMinGswDialogCommand(connectionContext?: azdata.ObjectExplorerContext): Promise<void> {
if (!connectionContext) {
vscode.window.showErrorMessage(localize('adminToolExtWin.noConnectionContextForGsw', 'No ConnectionContext provided for handleLaunchSsmsMinPropertiesDialogCommand'));
}
launchSsmsDialog(
'GenerateScripts',
connectionContext);
} }
/** /**
@@ -96,29 +169,72 @@ function handleLaunchSsmsServerPropertiesDialogCommand(connectionContext?: azdat
* @param params The params used to construct the command * @param params The params used to construct the command
* @param urn The URN to pass to SsmsMin * @param urn The URN to pass to SsmsMin
*/ */
function launchSsmsDialog(action: string, connectionProfile: azdata.IConnectionProfile, urn?: string) { async function launchSsmsDialog(action: string, connectionContext: azdata.ObjectExplorerContext): Promise<void> {
if (!exePath) { if (!exePath) {
vscode.window.showErrorMessage(localize('adminToolExtWin.noExeError', 'Unable to find SsmsMin.exe.')); vscode.window.showErrorMessage(localize('adminToolExtWin.noExeError', 'Unable to find SsmsMin.exe.'));
return; return;
} }
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 = { let params: LaunchSsmsDialogParams = {
action: action, action: action,
server: connectionProfile.serverName, server: connectionContext.connectionProfile.serverName,
database: connectionProfile.databaseName, database: connectionContext.connectionProfile.databaseName,
password: connectionProfile.password, user: connectionContext.connectionProfile.userName,
user: connectionProfile.userName, useAad: connectionContext.connectionProfile.authenticationType === 'AzureMFA',
useAad: connectionProfile.authenticationType === 'AzureMFA',
urn: urn urn: urn
}; };
let args = buildSsmsMinCommandArgs(params); let args = buildSsmsMinCommandArgs(params);
Telemetry.sendTelemetryEvent('LaunchSsmsDialog', { 'action': action });
// This will be an async call since we pass in the callback // This will be an async call since we pass in the callback
var proc: ChildProcess = exec( let proc: ChildProcess = exec(
/*command*/`"${exePath}" ${args}`, /*command*/ `"${exePath}" ${args}`,
/*options*/undefined, /*options*/ undefined,
(execException, stdout, stderr) => { (execException, stdout, stderr) => {
// Process has exited so remove from map of running processes // Process has exited so remove from map of running processes
runningProcesses.delete(proc.pid); runningProcesses.delete(proc.pid);
@@ -128,13 +244,15 @@ function launchSsmsDialog(action: string, connectionProfile: azdata.IConnectionP
}); });
let err = stderr.toString(); let err = stderr.toString();
if (err !== '') { 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 we're not using AAD the tool prompts for a password on stdin
if (params.useAad !== true) { 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 // 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 * @param params The params used to build up the command parameter string
*/ */
export function buildSsmsMinCommandArgs(params: LaunchSsmsDialogParams): string { export function buildSsmsMinCommandArgs(params: LaunchSsmsDialogParams): string {
return `${params.action ? '-a "' + params.action.replace(/"/g, '\\"') + '"' : ''}\ return `${params.action ? '-a "' + backEscapeDoubleQuotes(params.action) + '"' : ''}\
${params.server ? ' -S "' + params.server.replace(/"/g, '\\"') + '"' : ''}\ ${params.server ? ' -S "' + backEscapeDoubleQuotes(params.server) + '"' : ''}\
${params.database ? ' -D "' + params.database.replace(/"/g, '\\"') + '"' : ''}\ ${params.database ? ' -D "' + backEscapeDoubleQuotes(params.database) + '"' : ''}\
${params.useAad !== true && params.user ? ' -U "' + params.user.replace(/"/g, '\\"') + '"' : ''}\ ${params.useAad !== true && params.user ? ' -U "' + backEscapeDoubleQuotes(params.user) + '"' : ''}\
${params.useAad === true ? ' -G' : ''}\ ${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('/');
} }

View File

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

View File

@@ -9,20 +9,20 @@ const testRunner = require('vscode/lib/testrunner');
const suite = 'Database Admin Tool Extensions for Windows'; const suite = 'Database Admin Tool Extensions for Windows';
const options: any = { const options: any = {
ui: 'bdd', ui: 'bdd',
useColors: true, useColors: true,
timeout: 600000 timeout: 600000
}; };
if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) {
options.reporter = 'mocha-multi-reporters'; options.reporter = 'mocha-multi-reporters';
options.reporterOptions = { options.reporterOptions = {
reporterEnabled: 'spec, mocha-junit-reporter', reporterEnabled: 'spec, mocha-junit-reporter',
mochaJunitReporterReporterOptions: { mochaJunitReporterReporterOptions: {
testsuitesTitle: `${suite} ${process.platform}`, testsuitesTitle: `${suite} ${process.platform}`,
mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`)
} }
}; };
} }
testRunner.configure(options); testRunner.configure(options);

View 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);
}
}

View File

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

View File

@@ -7,19 +7,19 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
export interface IPackageInfo { export interface IPackageInfo {
name: string; name: string;
version: string; version: string;
aiKey: string; aiKey: string;
} }
export function getPackageInfo(packageJson: any): IPackageInfo { export function getPackageInfo(packageJson: any): IPackageInfo {
if (packageJson) { if (packageJson) {
return { return {
name: packageJson.name, name: packageJson.name,
version: packageJson.version, version: packageJson.version,
aiKey: packageJson.aiKey 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 * @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 { export function getConfiguration(extensionName?: string, resource?: vscode.Uri | string): vscode.WorkspaceConfiguration {
if (typeof resource === 'string') { if (typeof resource === 'string') {
try { try {
resource = this.parseUri(resource); resource = this.parseUri(resource);
} catch (e) { } catch (e) {
resource = undefined; resource = undefined;
} }
} else if (!resource) { } else if (!resource) {
// Fix to avoid adding lots of errors to debug console. Expects a valid resource or null, not undefined // Fix to avoid adding lots of errors to debug console. Expects a valid resource or null, not undefined
resource = null; resource = null;
} }
return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri); return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri);
}
/**
* Escapes all single-quotes (') by prefixing them with another single quote ('')
* ' => ''
* @param value The string to escape
*/
export function doubleEscapeSingleQuotes(value: string): string {
return value.replace(/'/g, '\'\'');
}
/**
* Escape all double-quotes (") by prefixing them with a \
* " => \"
* @param value The string to escape
*/
export function backEscapeDoubleQuotes(value: string): string {
return value.replace(/"/g, '\\"');
} }

View File

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

2710
extensions/agent/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,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'; 'use strict';
import * as azdata from 'azdata'; import * as azdata from 'azdata';

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as data from 'azdata'; import * as data from 'azdata';
@@ -12,52 +11,51 @@ import * as data from 'azdata';
* this API from our code * this API from our code
* *
* @export * @export
* @class ApiWrapper
*/ */
export class ApiWrapper { export class ApiWrapper {
// Data APIs // Data APIs
public registerWebviewProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void { public registerWebviewProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void {
return data.dashboard.registerWebviewProvider(widgetId, handler); return data.dashboard.registerWebviewProvider(widgetId, handler);
} }
public registerControlHostProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void { public registerControlHostProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void {
return data.dashboard.registerWebviewProvider(widgetId, handler); return data.dashboard.registerWebviewProvider(widgetId, handler);
} }
/** /**
* Get the configuration for a extensionName * Get the configuration for a extensionName
* @param extensionName The string name of the extension to get the configuration for * @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 * @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 { public getConfiguration(extensionName: string, resource?: vscode.Uri | string): vscode.WorkspaceConfiguration {
if (typeof resource === 'string') { if (typeof resource === 'string') {
try { try {
resource = this.parseUri(resource); resource = this.parseUri(resource);
} catch (e) { } catch (e) {
resource = undefined; resource = undefined;
} }
} }
return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri); return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri);
} }
/** /**
* Parse uri * Parse uri
*/ */
public parseUri(uri: string): vscode.Uri { public parseUri(uri: string): vscode.Uri {
return vscode.Uri.parse(uri); return vscode.Uri.parse(uri);
} }
public showOpenDialog(options: vscode.OpenDialogOptions): Thenable<vscode.Uri[] | undefined> { public showOpenDialog(options: vscode.OpenDialogOptions): Thenable<vscode.Uri[] | undefined> {
return vscode.window.showOpenDialog(options); return vscode.window.showOpenDialog(options);
} }
public showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> { public showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> {
return vscode.window.showErrorMessage(message, ...items); return vscode.window.showErrorMessage(message, ...items);
} }
public get workspaceRootPath(): string { public get workspaceRootPath(): string {
return vscode.workspace.rootPath; return vscode.workspace.rootPath;
} }
} }

View File

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

View File

@@ -14,7 +14,7 @@ const localize = nls.loadMessageBundle();
export class JobData implements IAgentDialogData { 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_OnFailure: string = localize('jobData.whenJobFails', 'When the job fails');
private readonly JobCompletionActionCondition_OnSuccess: string = localize('jobData.whenJobSucceeds', 'When the job succeeds'); private readonly JobCompletionActionCondition_OnSuccess: string = localize('jobData.whenJobSucceeds', 'When the job succeeds');
@@ -126,7 +126,7 @@ export class JobData implements IAgentDialogData {
public async save() { public async save() {
let jobInfo: azdata.AgentJobInfo = this.toAgentJobInfo(); let jobInfo: azdata.AgentJobInfo = this.toAgentJobInfo();
let result = this.dialogMode === AgentDialogMode.CREATE 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); : await this._agentService.updateJob(this.ownerUri, this.originalName, jobInfo);
if (!result || !result.success) { if (!result || !result.success) {
if (this.dialogMode === AgentDialogMode.EDIT) { if (this.dialogMode === AgentDialogMode.EDIT) {
@@ -142,7 +142,7 @@ export class JobData implements IAgentDialogData {
localize('jobData.saveSucessMessage', "Job '{0}' updated successfully", jobInfo.name)); localize('jobData.saveSucessMessage', "Job '{0}' updated successfully", jobInfo.name));
} else { } else {
vscode.window.showInformationMessage( vscode.window.showInformationMessage(
localize('jobData.newJobSuccessMessage',"Job '{0}' created successfully", jobInfo.name)); localize('jobData.newJobSuccessMessage', "Job '{0}' created successfully", jobInfo.name));
} }
} }

View File

@@ -48,7 +48,7 @@ export class JobStepData implements IAgentDialogData {
private jobModel: JobData; private jobModel: JobData;
private viaJobDialog: boolean; private viaJobDialog: boolean;
constructor(ownerUri:string, jobModel?: JobData, viaJobDialog: boolean = false) { constructor(ownerUri: string, jobModel?: JobData, viaJobDialog: boolean = false) {
this.ownerUri = ownerUri; this.ownerUri = ownerUri;
this.jobName = jobModel.name; this.jobName = jobModel.name;
this.jobModel = jobModel; this.jobModel = jobModel;
@@ -102,26 +102,26 @@ export class JobStepData implements IAgentDialogData {
stepData.jobName = jobStepInfo.jobName; stepData.jobName = jobStepInfo.jobName;
stepData.script = jobStepInfo.script; stepData.script = jobStepInfo.script;
stepData.scriptName = jobStepInfo.scriptName, stepData.scriptName = jobStepInfo.scriptName,
stepData.stepName = jobStepInfo.stepName, stepData.stepName = jobStepInfo.stepName,
stepData.subSystem = jobStepInfo.subSystem, stepData.subSystem = jobStepInfo.subSystem,
stepData.id = jobStepInfo.id, stepData.id = jobStepInfo.id,
stepData.failureAction = jobStepInfo.failureAction, stepData.failureAction = jobStepInfo.failureAction,
stepData.successAction = jobStepInfo.successAction, stepData.successAction = jobStepInfo.successAction,
stepData.failStepId = jobStepInfo.failStepId, stepData.failStepId = jobStepInfo.failStepId,
stepData.successStepId = jobStepInfo.successStepId, stepData.successStepId = jobStepInfo.successStepId,
stepData.command = jobStepInfo.command, stepData.command = jobStepInfo.command,
stepData.commandExecutionSuccessCode = jobStepInfo.commandExecutionSuccessCode, stepData.commandExecutionSuccessCode = jobStepInfo.commandExecutionSuccessCode,
stepData.databaseName = jobStepInfo.databaseName, stepData.databaseName = jobStepInfo.databaseName,
stepData.databaseUserName = jobStepInfo.databaseUserName, stepData.databaseUserName = jobStepInfo.databaseUserName,
stepData.server = jobStepInfo.server, stepData.server = jobStepInfo.server,
stepData.outputFileName = jobStepInfo.outputFileName, stepData.outputFileName = jobStepInfo.outputFileName,
stepData.appendToLogFile = jobStepInfo.appendToLogFile, stepData.appendToLogFile = jobStepInfo.appendToLogFile,
stepData.appendToStepHist = jobStepInfo.appendToStepHist, stepData.appendToStepHist = jobStepInfo.appendToStepHist,
stepData.writeLogToTable = jobStepInfo.writeLogToTable, stepData.writeLogToTable = jobStepInfo.writeLogToTable,
stepData.appendLogToTable = jobStepInfo.appendLogToTable, stepData.appendLogToTable = jobStepInfo.appendLogToTable,
stepData.retryAttempts = jobStepInfo.retryAttempts, stepData.retryAttempts = jobStepInfo.retryAttempts,
stepData.retryInterval = jobStepInfo.retryInterval, stepData.retryInterval = jobStepInfo.retryInterval,
stepData.proxyName = jobStepInfo.proxyName; stepData.proxyName = jobStepInfo.proxyName;
stepData.dialogMode = AgentDialogMode.EDIT; stepData.dialogMode = AgentDialogMode.EDIT;
stepData.viaJobDialog = true; stepData.viaJobDialog = true;
return stepData; return stepData;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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();
});
});

View 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);
});
});

View 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;

View File

@@ -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 {
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -3,16 +3,19 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
// localizable strings //@ts-check
export const InvalidProvider = 'Provider is invalid'; 'use strict';
/** const withDefaults = require('../shared.webpack.config');
* Feature names
*/
export const RestoreFeatureName = 'restore';
export const BackupFeatureName = 'backup';
export const MssqlProviderId = 'MSSQL';
export const notebookModeId = 'notebook';
module.exports = withDefaults({
context: __dirname,
entry: {
extension: './src/extension.ts'
},
externals: {
'ms-rest': 'commonjs ms-rest',
'request': 'commonjs request'
}
});

View File

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

View File

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

View File

@@ -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

View File

@@ -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

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -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

View File

@@ -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

View File

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

View File

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

View File

@@ -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'; 'use strict';
import * as azdata from 'azdata'; import * as azdata from 'azdata';

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,10 +17,10 @@ export class AzureResourceCacheService implements IAzureResourceCacheService {
} }
public generateKey(id: string): string { 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); return this._context.workspaceState.get(key);
} }

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