Merge branch 'main' into bmw/esbuild

This commit is contained in:
Brandon Waterloo [MSFT] 2023-10-11 11:00:01 -04:00
Родитель 6c2b970277 295d81ca1e
Коммит ada839ed3d
216 изменённых файлов: 1819 добавлений и 11495 удалений

Просмотреть файл

@ -1,3 +1,23 @@
## 1.27.0 - 16 October 2023
### Added
- Enhanced registries functionality: [#869](https://github.com/microsoft/vscode-docker/issues/869)
- Allows third party providers to contribute to the registries view.
- Added GitHub Container Registry support.
- GitLab Container Registry support will be moved to a separate extension. We will provide a link to install once it's published.
### Fixed
- Resolved issues with opening .NET web apps in browsers built with .NET SDK containers. [#4006](https://github.com/microsoft/vscode-docker/issues/4006)
- Fixed several Dockerfile language server issues. [#4056](https://github.com/microsoft/vscode-docker/issues/4056), [#4054](https://github.com/microsoft/vscode-docker/issues/4054), [#4051](https://github.com/microsoft/vscode-docker/issues/4051), [#4012](https://github.com/microsoft/vscode-docker/issues/4012)
## 1.26.1 - 13 September 2023
### Added
- Updated .NET Dockerfile scaffolding to utilize the latest .NET 8 image names. [#4015](https://github.com/microsoft/vscode-docker/issues/4015)
- Added support for multiple .dockerignore file naming conventions specific to language modes. [#4059](https://github.com/microsoft/vscode-docker/issues/4059)
- Integrated the container client package. [#3982](https://github.com/microsoft/vscode-docker/pull/3982)
### Fixed
- Enhanced debugging experience on arm64 machines. [#4040](https://github.com/microsoft/vscode-docker/issues/4040)
## 1.26.0 - 10 July 2023
### Added
* Added support for debugging .NET projects with .NET SDK container build. [#3808](https://github.com/microsoft/vscode-docker/issues/3808)

665
NOTICE.html поставляемый
Просмотреть файл

@ -1563,74 +1563,6 @@ END OF TERMS AND CONDITIONS
</pre>
</details>
</li>
<li>
<details>
<summary>
typescript 1.0.0 - Apache-2.0
</summary>
<p><a href="http://typescriptlang.org/">http://typescriptlang.org/</a></p>
<ul><li>Copyright (c) Microsoft Corporation.</li>
<li>Copyright (c) 2010-2011 Dojo Foundation.</li></ul>
<pre>
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
&quot;License&quot; shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
&quot;Licensor&quot; shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
&quot;Legal Entity&quot; shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, &quot;control&quot; means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
&quot;You&quot; (or &quot;Your&quot;) shall mean an individual or Legal Entity exercising permissions granted by this License.
&quot;Source&quot; form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
&quot;Object&quot; form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
&quot;Work&quot; shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
&quot;Derivative Works&quot; shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
&quot;Contribution&quot; shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, &quot;submitted&quot; means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as &quot;Not a Contribution.&quot;
&quot;Contributor&quot; shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of this License; and
You must cause any modified files to carry prominent notices stating that You changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
If the Work includes a &quot;NOTICE&quot; text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -1698,78 +1630,6 @@ If the Work includes a &quot;NOTICE&quot; text file as part of its distribution,
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
</pre>
</details>
</li>
<li>
<details>
<summary>
typescript 5.1.3 - Apache-2.0
</summary>
<p><a href="https://www.typescriptlang.org/">https://www.typescriptlang.org/</a></p>
<ul><li>(c) by W3C</li>
<li>Copyright (c) 2018 WHATWG</li>
<li>Copyright (c) Microsoft Corporation</li>
<li>Copyright (c) 1991-2017 Unicode, Inc.</li>
<li>Copyright (c) 2018 The Khronos Group Inc.</li>
<li>Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers</li></ul>
<pre>
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
&quot;License&quot; shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
&quot;Licensor&quot; shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
&quot;Legal Entity&quot; shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, &quot;control&quot; means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
&quot;You&quot; (or &quot;Your&quot;) shall mean an individual or Legal Entity exercising permissions granted by this License.
&quot;Source&quot; form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
&quot;Object&quot; form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
&quot;Work&quot; shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
&quot;Derivative Works&quot; shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
&quot;Contribution&quot; shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, &quot;submitted&quot; means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as &quot;Not a Contribution.&quot;
&quot;Contributor&quot; shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of this License; and
You must cause any modified files to carry prominent notices stating that You changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
If the Work includes a &quot;NOTICE&quot; text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
</pre>
@ -2734,49 +2594,6 @@ POSSIBILITY OF SUCH DAMAGE.
</pre>
</details>
</li>
<li>
<details>
<summary>
diff 1.0.0 - BSD-3-Clause
</summary>
<ul><li>Copyright (c) 2009-2011, Kevin Decker kpdecker@gmail.com</li>
<li>Copyright (c) 2009-2011, Kevin Decker &lt;kpdecker@gmail.com&gt;</li></ul>
<pre>
Software License Agreement (BSD License)
Copyright (c) 2009-2011, Kevin Decker &lt;kpdecker@gmail.com&gt;
All rights reserved.
Redistribution and use of this software in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of Kevin Decker nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot; AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -4068,26 +3885,6 @@ PERFORMANCE OF THIS SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
ini 1.0.0 - ISC
</summary>
<pre>
ISC License
Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. (&quot;ISC&quot;)
Copyright (c) 1995-2003 by Internet Software Consortium
Permission to use, copy, modify, and /or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot; AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -4115,46 +3912,6 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
javascript 1.0.0 - ISC
</summary>
<p><a href="https://github.com/npm/deprecate-holder#readme">https://github.com/npm/deprecate-holder#readme</a></p>
<pre>
ISC License
Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. (&quot;ISC&quot;)
Copyright (c) 1995-2003 by Internet Software Consortium
Permission to use, copy, modify, and /or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot; AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
julia 1.0.0 - ISC
</summary>
<p><a href="https://github.com/npm/deprecate-holder#readme">https://github.com/npm/deprecate-holder#readme</a></p>
<pre>
ISC License
Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. (&quot;ISC&quot;)
Copyright (c) 1995-2003 by Internet Software Consortium
Permission to use, copy, modify, and /or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot; AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -4482,7 +4239,7 @@ License, as follows:
<li>
<details>
<summary>
semver 5.7.1 - ISC
semver 5.7.2 - ISC
</summary>
<p><a href="https://github.com/npm/node-semver#readme">https://github.com/npm/node-semver#readme</a></p>
<ul><li>Copyright Isaac Z.</li>
@ -4511,7 +4268,7 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
<li>
<details>
<summary>
semver 7.5.0 - ISC
semver 7.5.2 - ISC
</summary>
<p><a href="https://github.com/npm/node-semver#readme">https://github.com/npm/node-semver#readme</a></p>
<ul><li>Copyright Isaac Z. Schlueter</li>
@ -4669,31 +4426,6 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
yaml 1.0.0 - ISC
</summary>
<p><a href="https://eemeli.org/yaml/">https://eemeli.org/yaml/</a></p>
<ul><li>Copyright 2018 Eemeli Aro &lt;eemeli@gmail.com&gt;</li></ul>
<pre>
Copyright 2018 Eemeli Aro &lt;eemeli@gmail.com&gt;
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot; AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -4746,6 +4478,41 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@aashutoshrathi/word-wrap 1.2.6 - MIT
</summary>
<p><a href="https://github.com/aashutoshrathi/word-wrap">https://github.com/aashutoshrathi/word-wrap</a></p>
<ul><li>Copyright (c) 2014-2016, Jon Schlinkert</li>
<li>Copyright (c) 2014-2023, Jon Schlinkert</li>
<li>Copyright (c) 2017, Jon Schlinkert (https://github.com/jonschlinkert)</li></ul>
<pre>
The MIT License (MIT)
Copyright (c) 2014-2016, Jon Schlinkert
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the &quot;Software&quot;), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -8538,39 +8305,6 @@ THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
coffeescript 1.0.0 - MIT
</summary>
<ul><li>Copyright (c) 2010 Jeremy Ashkenas</li></ul>
<pre>
Copyright (c) 2010 Jeremy Ashkenas
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the &quot;Software&quot;), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -8989,26 +8723,6 @@ THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
css 1.0.0 - MIT
</summary>
<ul><li>Copyright (c) 2012 TJ Holowaychuk &lt;tj@vision-media.ca&gt;</li></ul>
<pre>
MIT License
Copyright (c) &lt;year&gt; &lt;copyright holders&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -9271,39 +8985,6 @@ furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
docker 1.0.0 - MIT
</summary>
<p><a href="http://jbt.github.com/docker">http://jbt.github.com/docker</a></p>
<ul><li>Copyright (c) 2015 James Taylor</li></ul>
<pre>
The MIT License (MIT)
Copyright (c) 2015 James Taylor
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the &quot;Software&quot;), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -10311,27 +9992,6 @@ SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
github 0.0.1 - MIT
</summary>
<p><a href="http://github.com/ajaxorg/node-github.git">http://github.com/ajaxorg/node-github.git</a></p>
<ul><li>Copyright 2010 Ajax.org B.V.</li>
<li>Copyright (c) 2010 ajax.org B.V</li></ul>
<pre>
MIT License
Copyright (c) &lt;year&gt; &lt;copyright holders&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -10395,26 +10055,6 @@ THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRES
</pre>
</details>
</li>
<li>
<details>
<summary>
go 1.0.0 - MIT
</summary>
<pre>
MIT License
Copyright (c) &lt;year&gt; &lt;copyright holders&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -10447,84 +10087,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
grunt 1.0.0 - MIT
</summary>
<p><a href="http://gruntjs.com/">http://gruntjs.com/</a></p>
<ul><li>Copyright jQuery Foundation and other contributors, https://jquery.org</li></ul>
<pre>
Copyright jQuery Foundation and other contributors, https://jquery.org/
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history
available at https://github.com/gruntjs/grunt .
The following license applies to all parts of this software except as
documented below:
====
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
&quot;Software&quot;), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====
All files located in the node_modules directory are externally maintained
libraries used by this software which have their own licenses; we recommend
you read them, as their terms may differ from the terms above.
</pre>
</details>
</li>
<li>
<details>
<summary>
gulp 1.0.0 - MIT
</summary>
<p><a href="http://github.com/wearefractal/gulp">http://github.com/wearefractal/gulp</a></p>
<ul><li>Copyright (c) 2013 Fractal &lt;contact@wearefractal.com&gt;</li></ul>
<pre>
Copyright (c) 2013 Fractal &lt;contact@wearefractal.com&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
&quot;Software&quot;), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
</details>
</li>
@ -10723,28 +10285,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
html 1.0.0 - MIT
</summary>
<p><a href="https://github.com/maxogden/commonjs-html-prettyprinter">https://github.com/maxogden/commonjs-html-prettyprinter</a></p>
<ul><li>Copyright (c) 2014-2015 Max Ogden and contributors</li>
<li>Copyright (c) 2007-2013 Einar Lielmanis and contributors.</li></ul>
<pre>
The MIT License (MIT)
Copyright (c) 2014-2015 Max Ogden and contributors
Copyright (c) 2007-2013 Einar Lielmanis and contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -11060,26 +10600,6 @@ SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
ipynb 1.0.0 - MIT
</summary>
<p><a href="https://github.com/finnp/ipynb">https://github.com/finnp/ipynb</a></p>
<pre>
MIT License
Copyright (c) &lt;year&gt; &lt;copyright holders&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -12139,26 +11659,6 @@ terms above.
</pre>
</details>
</li>
<li>
<details>
<summary>
log 1.0.0 - MIT
</summary>
<ul><li>Copyright (c) 2010 TJ Holowaychuk &lt;tj@vision-media.ca&gt;</li></ul>
<pre>
MIT License
Copyright (c) &lt;year&gt; &lt;copyright holders&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -12943,7 +12443,7 @@ SOFTWARE.
<li>
<details>
<summary>
optionator 0.9.1 - MIT
optionator 0.9.3 - MIT
</summary>
<p><a href="https://github.com/gkz/optionator">https://github.com/gkz/optionator</a></p>
<ul><li>Copyright (c) George Zahariev</li></ul>
@ -14598,41 +14098,6 @@ SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
swift 1.0.0 - MIT
</summary>
<p><a href="http://github.com/131/swift">http://github.com/131/swift</a></p>
<ul><li>Copyright (c) 2018 - Francois Leurent</li></ul>
<pre>
Copyright (c) 2018 - Francois Leurent
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the &quot;Software&quot;), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Except as contained in this notice, the name of OVH and or its trademarks
shall not be used in advertising or otherwise to promote the sale, use or other
dealings in this Software without prior written authorization from OVH.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -15331,26 +14796,6 @@ THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRES
</pre>
</details>
</li>
<li>
<details>
<summary>
vscode-json-languageserver 1.3.4 - MIT
</summary>
<ul><li>Copyright (c) Microsoft Corporation.</li></ul>
<pre>
MIT License
Copyright (c) &lt;year&gt; &lt;copyright holders&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
@ -15924,40 +15369,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>
xml 1.0.0 - MIT
</summary>
<p><a href="http://github.com/dylang/node-xml">http://github.com/dylang/node-xml</a></p>
<ul><li>Copyright (c) 2011 Dylan Greene &lt;dylang@gmail.com&gt;</li>
<li>Copyright (c) 2011-2014 Dylan Greene &lt;dylang@gmail.com&gt;</li></ul>
<pre>
(The MIT License)
Copyright (c) 2011 Dylan Greene &lt;dylang@gmail.com&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
&#39;Software&#39;), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED &#39;AS IS&#39;, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
</details>
</li>
<li>
<details>
<summary>

203
package-lock.json сгенерированный
Просмотреть файл

@ -1,30 +1,32 @@
{
"name": "vscode-docker",
"version": "1.26.0",
"version": "1.27.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "vscode-docker",
"version": "1.26.0",
"version": "1.27.0",
"license": "SEE LICENSE IN LICENSE.md",
"dependencies": {
"@azure/arm-authorization": "^9.0.0",
"@azure/arm-containerregistry": "^10.1.0",
"@azure/storage-blob": "^12.14.0",
"@microsoft/compose-language-service": "^0.2.0",
"@microsoft/vscode-azext-azureappservice": "^1.0.2",
"@microsoft/vscode-azext-azureutils": "^1.1.5",
"@microsoft/vscode-azext-utils": "^1.2.2",
"@microsoft/vscode-azext-azureappservice": "~2.0",
"@microsoft/vscode-azext-azureauth": "^1.1.2",
"@microsoft/vscode-azext-azureutils": "^2.0.0",
"@microsoft/vscode-azext-utils": "^2.1.1",
"@microsoft/vscode-container-client": "^0.1.0",
"@microsoft/vscode-docker-registries": "^0.1.3",
"dayjs": "^1.11.7",
"dockerfile-language-server-nodejs": "^0.10.2",
"dockerfile-language-server-nodejs": "^0.11.0",
"fs-extra": "^11.1.1",
"gradle-to-js": "^2.0.1",
"handlebars": "^4.7.7",
"node-fetch": "^2.6.9",
"semver": "^7.5.2",
"tar": "^6.1.13",
"tree-kill": "^1.2.2",
"vscode-languageclient": "^8.1.0",
"vscode-tas-client": "^0.1.63",
"xml2js": "^0.5.0"
@ -257,6 +259,23 @@
"node": ">=14.0.0"
}
},
"node_modules/@azure/arm-subscriptions": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@azure/arm-subscriptions/-/arm-subscriptions-5.1.0.tgz",
"integrity": "sha512-6BeOF2eQWNLq22ch7xP9RxYnPjtGev54OUCGggKOWoOvmesK7jUZbIyLk8JeXDT21PEl7iyYnxw78gxJ7zBxQw==",
"dependencies": {
"@azure/abort-controller": "^1.0.0",
"@azure/core-auth": "^1.3.0",
"@azure/core-client": "^1.6.1",
"@azure/core-lro": "^2.2.0",
"@azure/core-paging": "^1.2.0",
"@azure/core-rest-pipeline": "^1.8.0",
"tslib": "^2.2.0"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@azure/core-auth": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.4.0.tgz",
@ -403,8 +422,7 @@
"node_modules/@azure/ms-rest-azure-env": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@azure/ms-rest-azure-env/-/ms-rest-azure-env-2.0.0.tgz",
"integrity": "sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw==",
"peer": true
"integrity": "sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw=="
},
"node_modules/@azure/storage-blob": {
"version": "12.14.0",
@ -1030,9 +1048,9 @@
"integrity": "sha512-n1VPsljTSkthsAFYdiWfC+DKzK2WwcRp83Y1YAqdX552BstvsDjft9YXppjUzp11BPsapDoO1LDgrDB0XVsfNQ=="
},
"node_modules/@microsoft/vscode-azext-azureappservice": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureappservice/-/vscode-azext-azureappservice-1.0.2.tgz",
"integrity": "sha512-YaKqYIkeX0kH8KgUsUOUrr7RA9ghtFnZXcS8RfSIs6/HmssN3pYdKEjlq4Yq3U5oOkX8Cq5xlujHoCiUaUsh7Q==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureappservice/-/vscode-azext-azureappservice-2.0.0.tgz",
"integrity": "sha512-evtnwjKZk6wBGXJQy3sNEEFdGztQAT09HeuyU4qpFwWRBIoPE1wg0TO7S7psc+N5W8sFiWBy3h15mOlU6daocA==",
"dependencies": {
"@azure/abort-controller": "^1.0.4",
"@azure/arm-appinsights": "^5.0.0-beta.4",
@ -1043,8 +1061,8 @@
"@azure/core-client": "^1.7.2",
"@azure/core-rest-pipeline": "^1.10.3",
"@azure/storage-blob": "^12.3.0",
"@microsoft/vscode-azext-azureutils": "^1.1.5",
"@microsoft/vscode-azext-utils": "^1.2.2",
"@microsoft/vscode-azext-azureutils": "^2.0.0",
"@microsoft/vscode-azext-utils": "^2.0.0",
"dayjs": "^1.11.2",
"fs-extra": "^10.0.0",
"globby": "^11.0.2",
@ -1056,7 +1074,7 @@
},
"peerDependencies": {
"@azure/ms-rest-azure-env": "^2.0.0",
"@microsoft/vscode-azext-azureappsettings": "^0.1.0"
"@microsoft/vscode-azext-azureappsettings": "^0.2.0"
}
},
"node_modules/@microsoft/vscode-azext-azureappservice/node_modules/fs-extra": {
@ -1073,18 +1091,27 @@
}
},
"node_modules/@microsoft/vscode-azext-azureappsettings": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureappsettings/-/vscode-azext-azureappsettings-0.1.0.tgz",
"integrity": "sha512-oxq3tYgb9yt/Vxh8larmd3XTRW0FEaIfhtzEpZyb0YcqFaTEhY299J9oogiu78+dGDztgR3y8g0AhDHBpEmCiQ==",
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureappsettings/-/vscode-azext-azureappsettings-0.2.0.tgz",
"integrity": "sha512-fHv+m+dOluuYgPCQ7Mt8HoDgguWy8zHWofP3T6uxkuDF8VAJbjl9LFYHwV0frVcK4Qgxcj95QDjw5AMSUMHtqw==",
"peer": true,
"dependencies": {
"@microsoft/vscode-azext-utils": "^1.2.1"
"@microsoft/vscode-azext-utils": "^2.0.0"
}
},
"node_modules/@microsoft/vscode-azext-azureauth": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureauth/-/vscode-azext-azureauth-1.1.2.tgz",
"integrity": "sha512-cacmiEv1GiofOKaQzgRqXrDqPoFc3HAGiaer+ENNrdeW6elks0o5Z0oXkTIauS26yeYQUUaooB6DezvQU6LC+Q==",
"dependencies": {
"@azure/arm-subscriptions": "^5.1.0",
"@azure/ms-rest-azure-env": "^2.0.0"
}
},
"node_modules/@microsoft/vscode-azext-azureutils": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-1.1.5.tgz",
"integrity": "sha512-iG89BMp57ydHHl3NbW+T9vn/zksDOoYxgebAZmoF6fZzrIJn2VVmzWGllBsfBa1vEx/qDrvdfT6juSY0UtLe0w==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-2.0.2.tgz",
"integrity": "sha512-r+7NqedkvfFazztO7kxT1AU/B/UfiGhTDlRtFHx+W5bhp+yJw0eOtX8VPJXXSXoOaq2dzuGBwxAQ0bDD1lNPcQ==",
"dependencies": {
"@azure/arm-resources": "^5.0.0",
"@azure/arm-resources-profile-2020-09-01-hybrid": "^2.0.0",
@ -1094,7 +1121,7 @@
"@azure/core-client": "^1.6.0",
"@azure/core-rest-pipeline": "^1.9.0",
"@azure/logger": "^1.0.4",
"@microsoft/vscode-azext-utils": "^1.2.2",
"@microsoft/vscode-azext-utils": "^2.0.0",
"semver": "^7.3.7",
"uuid": "^9.0.0"
},
@ -1111,9 +1138,9 @@
}
},
"node_modules/@microsoft/vscode-azext-utils": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-1.2.2.tgz",
"integrity": "sha512-mOTcJF8IMsz+Xn8QTUP1AC3K5tPl/3f17L2xGTTtLeV/HJ2sTh/3712NFuN58tnOwdISdazId4tHwaqUta8HEA==",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-2.1.1.tgz",
"integrity": "sha512-MUrBET1YzS0QmpMY9ZcRjZe9/U0vmGtYI9hRTMB7NYBtutUF19+Y7W6k6G7Odlnn3MjRIrc8ZMmumvsVqlxhPg==",
"dependencies": {
"@microsoft/vscode-azureresources-api": "^2.0.4",
"@vscode/extension-telemetry": "^0.6.2",
@ -1142,6 +1169,24 @@
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azureresources-api/-/vscode-azureresources-api-2.0.4.tgz",
"integrity": "sha512-LridV1h2rCydrBzEpwy+pUIUx61GpZNwrK04G7LdlhoxHrzuM/WAoy8jXaSC/FSKSsXD1QXuE6u/YofEfsuKeg=="
},
"node_modules/@microsoft/vscode-container-client": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-container-client/-/vscode-container-client-0.1.0.tgz",
"integrity": "sha512-qA9xMZWH6JvhovJLlbxgyPRgtEj8cA7ktJtJPykJbycC+F/vwt1j2/GyWhrgwlkTlmmM1aGOnF9nSD84DGhABw==",
"dependencies": {
"dayjs": "^1.11.2",
"tree-kill": "^1.2.2"
}
},
"node_modules/@microsoft/vscode-docker-registries": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@microsoft/vscode-docker-registries/-/vscode-docker-registries-0.1.3.tgz",
"integrity": "sha512-3ORzbV3Ea764Nh3QuyGsqUTPTCk6T45KXBc+j7MUirJ39lUZAAeiXwAC85UHT40xPURhgQdqHdbhDz3kZ1Vw7g==",
"dependencies": {
"dayjs": "^1.11.7",
"node-fetch": "^2.6.11"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -2734,25 +2779,26 @@
"integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ=="
},
"node_modules/dockerfile-ast": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/dockerfile-ast/-/dockerfile-ast-0.5.0.tgz",
"integrity": "sha512-YsRrWww6mKRS1HK32gbherPlgfvwS593ZeDegb5glNCBJgByICAYZCP5F+njY6TSB0eiPdFgCU9RkuO516mLFQ==",
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/dockerfile-ast/-/dockerfile-ast-0.6.1.tgz",
"integrity": "sha512-m3rH2qHHU2pSTCppXgJT+1KLxhvkdROOxVPof5Yz4IPGSw6K+x0B0/RFdYgXN5zsIUTlbOSRyfDCv3/uVhnNmg==",
"dependencies": {
"vscode-languageserver-textdocument": "^1.0.1",
"vscode-languageserver-types": "^3.17.0-next.3"
"vscode-languageserver-textdocument": "^1.0.8",
"vscode-languageserver-types": "^3.17.3"
},
"engines": {
"node": "*"
}
},
"node_modules/dockerfile-language-server-nodejs": {
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/dockerfile-language-server-nodejs/-/dockerfile-language-server-nodejs-0.10.2.tgz",
"integrity": "sha512-vLbaeYv4h3XEzrZ9JOhP6bD1eLzbzGzFFF03F3Ofd6kh9PU2aGBS/LVjd/w1omCyNV2LHviFX0ZGHINmWsZYyw==",
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/dockerfile-language-server-nodejs/-/dockerfile-language-server-nodejs-0.11.0.tgz",
"integrity": "sha512-kv97EVYcKXh4SiteaVX8LDSwpcdAOIJM/3Wm6rWxTH4gLbozocDekoU5YpX1X2kKOI4L5gvzFIhzgxqPhFnRzg==",
"dependencies": {
"dockerfile-language-service": "0.10.2",
"dockerfile-utils": "0.11.0",
"vscode-languageserver": "^8.0.0-next.2"
"dockerfile-language-service": "0.11.0",
"dockerfile-utils": "0.15.0",
"vscode-languageserver": "~8.0.0",
"vscode-languageserver-textdocument": "~1.0.8"
},
"bin": {
"docker-langserver": "bin/docker-langserver"
@ -2761,27 +2807,61 @@
"node": "*"
}
},
"node_modules/dockerfile-language-service": {
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/dockerfile-language-service/-/dockerfile-language-service-0.10.2.tgz",
"integrity": "sha512-W561U9gj5Eol55j/hanLRPVarXDq+WXPai1lG5f1fW7/kYElsmWJZoRd585SQBahvC9VlJfFAs6IpzZlvN41Hg==",
"node_modules/dockerfile-language-server-nodejs/node_modules/vscode-jsonrpc": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz",
"integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/dockerfile-language-server-nodejs/node_modules/vscode-languageserver": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-8.0.2.tgz",
"integrity": "sha512-bpEt2ggPxKzsAOZlXmCJ50bV7VrxwCS5BI4+egUmure/oI/t4OlFzi/YNtVvY24A2UDOZAgwFGgnZPwqSJubkA==",
"dependencies": {
"dockerfile-ast": "0.5.0",
"dockerfile-utils": "0.11.0",
"vscode-languageserver-types": "3.17.0-next.3"
"vscode-languageserver-protocol": "3.17.2"
},
"bin": {
"installServerIntoExtension": "bin/installServerIntoExtension"
}
},
"node_modules/dockerfile-language-server-nodejs/node_modules/vscode-languageserver-protocol": {
"version": "3.17.2",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz",
"integrity": "sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg==",
"dependencies": {
"vscode-jsonrpc": "8.0.2",
"vscode-languageserver-types": "3.17.2"
}
},
"node_modules/dockerfile-language-server-nodejs/node_modules/vscode-languageserver-types": {
"version": "3.17.2",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz",
"integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA=="
},
"node_modules/dockerfile-language-service": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/dockerfile-language-service/-/dockerfile-language-service-0.11.0.tgz",
"integrity": "sha512-Y0TtqZNnI3EC5g/zCZitNV191oZoYCva2r6lt0T1k+W5VX1kjz0vwKbkgBIpk2Rzh4fQlYFJALALtvd/kw5ixA==",
"dependencies": {
"dockerfile-ast": "0.6.1",
"dockerfile-utils": "0.15.0",
"vscode-languageserver-textdocument": "1.0.8",
"vscode-languageserver-types": "3.17.3"
},
"engines": {
"node": "*"
}
},
"node_modules/dockerfile-utils": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/dockerfile-utils/-/dockerfile-utils-0.11.0.tgz",
"integrity": "sha512-b7uGmYAeneg/zP63vfUrkIWw4frvtviXe7QGV0Vw58kJwyEYmrKxjm+N+NbBgk6mwq5FEIDT5rx08pBpjstpEw==",
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/dockerfile-utils/-/dockerfile-utils-0.15.0.tgz",
"integrity": "sha512-hV2OExB797C3/GlOloywmMZzu3MPmzMziGuCaPWh/m9qHgTyfN4+EI3b6xhHDXy78PU0GqwvHnZVX7wfpqOCkg==",
"dependencies": {
"dockerfile-ast": "0.5.0",
"vscode-languageserver-textdocument": "^1.0.1",
"vscode-languageserver-types": "^3.17.0-next.3"
"dockerfile-ast": "0.6.1",
"vscode-languageserver-textdocument": "^1.0.8",
"vscode-languageserver-types": "^3.17.3"
},
"bin": {
"dockerfile-utils": "bin/dockerfile-utils"
@ -3509,9 +3589,9 @@
}
},
"node_modules/get-func-name": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
"integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
"integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
"dev": true,
"engines": {
"node": "*"
@ -4747,9 +4827,9 @@
"optional": true
},
"node_modules/node-fetch": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
"integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
"version": "2.6.12",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz",
"integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
@ -6300,20 +6380,15 @@
"vscode-languageserver-types": "3.17.3"
}
},
"node_modules/vscode-languageserver-protocol/node_modules/vscode-languageserver-types": {
"version": "3.17.3",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz",
"integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA=="
},
"node_modules/vscode-languageserver-textdocument": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz",
"integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q=="
},
"node_modules/vscode-languageserver-types": {
"version": "3.17.0-next.3",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.3.tgz",
"integrity": "sha512-VQcXnhKYxUW6OiRMhG++SzmZYMJwusXknJGd+FfdOnS1yHAo734OHyR0e2eEHDlv0/oWc8RZPgx/VKSKyondVg=="
"version": "3.17.3",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz",
"integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA=="
},
"node_modules/vscode-tas-client": {
"version": "0.1.63",

Просмотреть файл

@ -1,6 +1,6 @@
{
"name": "vscode-docker",
"version": "1.26.0",
"version": "1.27.0",
"publisher": "ms-azuretools",
"displayName": "Docker",
"description": "Makes it easy to create, manage, and debug containerized applications.",
@ -122,10 +122,6 @@
"command": "vscode-docker.registries.azure.buildImage",
"when": "isWorkspaceTrusted"
},
{
"command": "vscode-docker.registries.azure.runFileAsTask",
"when": "isWorkspaceTrusted"
},
{
"command": "vscode-docker.help.openWalkthrough",
"when": "never"
@ -145,19 +141,18 @@
{
"command": "vscode-docker.containers.group.remove",
"when": "never"
},
{
"command": "vscode-docker.activateRegistryProviders",
"when": "never"
}
],
"editor/context": [
{
"when": "isWorkspaceTrusted && editorLangId == dockerfile && isAzureAccountInstalled",
"when": "isWorkspaceTrusted && editorLangId == dockerfile",
"command": "vscode-docker.registries.azure.buildImage",
"group": "docker"
},
{
"when": "isWorkspaceTrusted && editorLangId == yaml && isAzureAccountInstalled",
"command": "vscode-docker.registries.azure.runFileAsTask",
"group": "docker"
},
{
"when": "isWorkspaceTrusted && editorLangId == dockercompose",
"command": "vscode-docker.compose.down",
@ -186,15 +181,10 @@
],
"explorer/context": [
{
"when": "isWorkspaceTrusted && resourceFilename =~ /dockerfile/i && isAzureAccountInstalled",
"when": "isWorkspaceTrusted && resourceFilename =~ /dockerfile/i",
"command": "vscode-docker.registries.azure.buildImage",
"group": "docker"
},
{
"when": "isWorkspaceTrusted && resourceLangId == yaml && isAzureAccountInstalled",
"command": "vscode-docker.registries.azure.runFileAsTask",
"group": "docker"
},
{
"when": "isWorkspaceTrusted && resourceLangId == dockercompose",
"command": "vscode-docker.compose.down",
@ -464,11 +454,6 @@
"when": "view == dockerRegistries && viewItem == azure;DockerV2;RegistryProvider;",
"group": "inline"
},
{
"command": "vscode-docker.registries.azure.viewTaskLogs",
"when": "view == dockerRegistries && viewItem == azureTaskRun",
"group": "inline"
},
{
"command": "vscode-docker.networks.inspect",
"when": "view == dockerNetworks && viewItem =~ /network$/i",
@ -481,102 +466,92 @@
},
{
"command": "vscode-docker.registries.azure.createRegistry",
"when": "view == dockerRegistries && viewItem == azureextensionui.azureSubscription",
"when": "view == dockerRegistries && viewItem =~ /azuresubscription/i",
"group": "regs_1_general@1"
},
{
"command": "vscode-docker.registries.azure.deleteRegistry",
"when": "view == dockerRegistries && viewItem == azure;DockerV2;Registry;",
"when": "view == dockerRegistries && viewItem =~ /azure;.*commonregistry/i",
"group": "regs_reg_2_destructive@1"
},
{
"command": "vscode-docker.registries.pullRepository",
"when": "view == dockerRegistries && viewItem =~ /Repository;/",
"when": "view == dockerRegistries && viewItem =~ /commonrepository/",
"group": "regs_repo_1_general@1"
},
{
"command": "vscode-docker.registries.azure.deleteRepository",
"when": "view == dockerRegistries && viewItem == azure;DockerV2;Repository;",
"when": "view == dockerRegistries && viewItem =~ /azure;.*commonrepository/i",
"group": "regs_repo_2_destructive@1"
},
{
"command": "vscode-docker.registries.pullImage",
"when": "view == dockerRegistries && viewItem =~ /Tag;/",
"when": "view == dockerRegistries && viewItem =~ /commontag/i",
"group": "regs_tag_1_general@1"
},
{
"command": "vscode-docker.registries.copyRemoteFullTag",
"when": "view == dockerRegistries && viewItem =~ /(DockerV2|DockerHubV2);Tag;/",
"when": "view == dockerRegistries && viewItem =~ /commontag/i",
"group": "regs_tag_1_general@2"
},
{
"command": "vscode-docker.registries.copyImageDigest",
"when": "view == dockerRegistries && viewItem =~ /DockerV2;Tag;/",
"when": "view == dockerRegistries && viewItem =~ /commontag/i && !(viewItem =~ /commontag;.*dockerhub/i)",
"group": "regs_tag_1_general@3"
},
{
"command": "vscode-docker.registries.deployImageToAzure",
"when": "view == dockerRegistries && viewItem =~ /(DockerV2|DockerHubV2);Tag;/ && isAzureAccountInstalled",
"when": "view == dockerRegistries && viewItem =~ /commontag/i",
"group": "regs_tag_1_general@4"
},
{
"command": "vscode-docker.registries.deployImageToAca",
"when": "view == dockerRegistries && viewItem =~ /(DockerV2|DockerHubV2|GitLabV4);Tag;/ && isAzureAccountInstalled",
"when": "view == dockerRegistries && viewItem =~ /commontag/i",
"group": "regs_tag_1_general@6"
},
{
"command": "vscode-docker.registries.azure.untagImage",
"when": "view == dockerRegistries && viewItem == azure;DockerV2;Tag;",
"when": "view == dockerRegistries && viewItem =~ /azure;.*commontag/i",
"group": "regs_tag_2_destructive@1"
},
{
"command": "vscode-docker.registries.deleteImage",
"when": "view == dockerRegistries && viewItem =~ /DockerV2;Tag;/",
"when": "view == dockerRegistries && viewItem =~ /commontag/i && !(viewItem =~ /commontag;.*(dockerhub|github)/i)",
"group": "regs_tag_2_destructive@2"
},
{
"command": "vscode-docker.registries.azure.runTask",
"when": "view == dockerRegistries && viewItem == azureTask",
"group": "regs_task_1_general@1"
},
{
"command": "vscode-docker.registries.copyImageDigest",
"when": "view == dockerRegistries && viewItem == azureTaskRun",
"group": "regs_taskRun_1_general@1"
},
{
"command": "vscode-docker.registries.azure.viewTaskLogs",
"when": "view == dockerRegistries && viewItem == azureTaskRun",
"group": "regs_taskRun_1_general@2"
},
{
"command": "vscode-docker.registries.disconnectRegistry",
"when": "view == dockerRegistries && viewItem =~ /RegistryProvider;/",
"when": "view == dockerRegistries && viewItem =~ /commonregistryroot/i && !(viewItem =~ /commonregistryroot;.*generic/i)",
"group": "regs_yyy_destructive@1"
},
{
"command": "vscode-docker.registries.disconnectRegistry",
"when": "view == dockerRegistries && viewItem == invalidRegistryProvider",
"command": "vscode-docker.registries.genericV2.removeTrackedRegistry",
"when": "view == dockerRegistries && viewItem =~ /commonregistry;.*generic/i",
"group": "regs_yyy_destructive@1"
},
{
"command": "vscode-docker.registries.genericV2.addTrackedRegistry",
"when": "view == dockerRegistries && viewItem =~ /commonregistryroot;.*generic/i",
"group": "regs_yyy_destructive@1"
},
{
"command": "vscode-docker.registries.azure.openInPortal",
"when": "view == dockerRegistries && viewItem =~ /azure(Subscription|;DockerV2;Registry;)/",
"when": "view == dockerRegistries && viewItem =~ /azuresubscription|azure;.*(commonregistry|commonrepository)/i",
"group": "regs_zzz_common@1"
},
{
"command": "vscode-docker.registries.dockerHub.openInBrowser",
"when": "view == dockerRegistries && viewItem =~ /dockerHub;DockerHubV2;(Tag|Repository|Registry);/",
"when": "view == dockerRegistries && viewItem =~ /(commonregistry|commonrepository|commontag);.*dockerhub/i",
"group": "regs_zzz_common@1"
},
{
"command": "vscode-docker.registries.azure.viewProperties",
"when": "view == dockerRegistries && viewItem =~ /azure(TaskRun|;DockerV2;Registry;)/",
"when": "view == dockerRegistries && viewItem =~ /azure;.*commonregistry/i",
"group": "regs_zzz_common@2"
},
{
"command": "vscode-docker.registries.reconnectRegistry",
"when": "view == dockerRegistries && viewItem == registryConnectError",
"when": "view == dockerRegistries && viewItem =~ /registryConnectError/i",
"group": "regs_zzz_common@8"
},
{
@ -586,12 +561,7 @@
},
{
"command": "vscode-docker.registries.refresh",
"when": "view == dockerRegistries && viewItem =~ /.*;.*;(Repository|Registry|RegistryProvider);/",
"group": "regs_zzz_common@9"
},
{
"command": "vscode-docker.registries.refresh",
"when": "view == dockerRegistries && viewItem =~ /azure(Subscription|Tasks|Task|RunsWithoutTask)$/",
"when": "view == dockerRegistries && viewItem =~ /commonregistry|commonregistryroot|commonrepository/",
"group": "regs_zzz_common@9"
},
{
@ -1558,6 +1528,9 @@
"id": "ignore",
"filenames": [
".dockerignore"
],
"filenamePatterns": [
"*.dockerignore"
]
}
],
@ -2598,16 +2571,6 @@
"title": "%vscode-docker.commands.registries.azure.openInPortal%",
"category": "%vscode-docker.commands.category.azureContainerRegistry%"
},
{
"command": "vscode-docker.registries.azure.runFileAsTask",
"title": "%vscode-docker.commands.registries.azure.runFileAsTask%",
"category": "%vscode-docker.commands.category.azureContainerRegistry%"
},
{
"command": "vscode-docker.registries.azure.runTask",
"title": "%vscode-docker.commands.registries.azure.runTask%",
"category": "%vscode-docker.commands.category.azureContainerRegistry%"
},
{
"command": "vscode-docker.registries.azure.selectSubscriptions",
"title": "%vscode-docker.commands.registries.azure.selectSubscriptions%",
@ -2623,12 +2586,6 @@
"title": "%vscode-docker.commands.registries.azure.viewProperties%",
"category": "%vscode-docker.commands.category.azureContainerRegistry%"
},
{
"command": "vscode-docker.registries.azure.viewTaskLogs",
"title": "%vscode-docker.commands.registries.azure.viewLogs%",
"category": "%vscode-docker.commands.category.azureContainerRegistry%",
"icon": "$(output)"
},
{
"command": "vscode-docker.registries.connectRegistry",
"title": "%vscode-docker.commands.registries.connect%",
@ -2665,6 +2622,16 @@
"title": "%vscode-docker.commands.registries.disconnectRegistry%",
"category": "%vscode-docker.commands.category.dockerRegistries%"
},
{
"command": "vscode-docker.registries.genericV2.removeTrackedRegistry",
"title": "%vscode-docker.commands.registries.genericV2.removeTrackedRegistry%",
"category": "%vscode-docker.commands.category.dockerRegistries%"
},
{
"command": "vscode-docker.registries.genericV2.addTrackedRegistry",
"title": "%vscode-docker.commands.registries.genericV2.addTrackedRegistry%",
"category": "%vscode-docker.commands.category.dockerRegistries%"
},
{
"command": "vscode-docker.registries.dockerHub.openInBrowser",
"title": "%vscode-docker.commands.registries.dockerHub.openInBrowser%",
@ -2784,6 +2751,11 @@
"title": "%vscode-docker.commands.contexts.help%",
"category": "%vscode-docker.commands.category.contexts%",
"icon": "$(question)"
},
{
"command": "vscode-docker.activateRegistryProviders",
"title": "%vscode-docker.commands.activateRegistryProviders%",
"category": "%vscode-docker.commands.category.docker%"
}
],
"views": {
@ -3024,18 +2996,20 @@
"@azure/arm-containerregistry": "^10.1.0",
"@azure/storage-blob": "^12.14.0",
"@microsoft/compose-language-service": "^0.2.0",
"@microsoft/vscode-azext-azureappservice": "^1.0.2",
"@microsoft/vscode-azext-azureutils": "^1.1.5",
"@microsoft/vscode-azext-utils": "^1.2.2",
"@microsoft/vscode-azext-azureappservice": "~2.0",
"@microsoft/vscode-azext-azureauth": "^1.1.2",
"@microsoft/vscode-azext-azureutils": "^2.0.0",
"@microsoft/vscode-azext-utils": "^2.1.1",
"@microsoft/vscode-container-client": "^0.1.0",
"@microsoft/vscode-docker-registries": "^0.1.3",
"dayjs": "^1.11.7",
"dockerfile-language-server-nodejs": "^0.10.2",
"dockerfile-language-server-nodejs": "^0.11.0",
"fs-extra": "^11.1.1",
"gradle-to-js": "^2.0.1",
"handlebars": "^4.7.7",
"node-fetch": "^2.6.9",
"semver": "^7.5.2",
"tar": "^6.1.13",
"tree-kill": "^1.2.2",
"vscode-languageclient": "^8.1.0",
"vscode-tas-client": "^0.1.63",
"xml2js": "^0.5.0"

Просмотреть файл

@ -262,12 +262,9 @@
"vscode-docker.commands.registries.azure.deleteRegistry": "Delete Registry...",
"vscode-docker.commands.registries.azure.deleteRepository": "Delete Repository...",
"vscode-docker.commands.registries.azure.openInPortal": "Open in Portal",
"vscode-docker.commands.registries.azure.runFileAsTask": "Run as Task in Azure...",
"vscode-docker.commands.registries.azure.runTask": "Run Task",
"vscode-docker.commands.registries.azure.selectSubscriptions": "Select Subscriptions...",
"vscode-docker.commands.registries.azure.untagImage": "Untag Image...",
"vscode-docker.commands.registries.azure.viewProperties": "View Properties",
"vscode-docker.commands.registries.azure.viewLogs": "View Logs",
"vscode-docker.commands.registries.connect": "Connect Registry...",
"vscode-docker.commands.registries.reconnectRegistry": "Re-enter credentials",
"vscode-docker.commands.registries.copyImageDigest": "Copy Image Digest",
@ -276,6 +273,8 @@
"vscode-docker.commands.registries.deployImageToAzure": "Deploy Image to Azure App Service...",
"vscode-docker.commands.registries.deployImageToAca": "Deploy Image to Azure Container Apps...",
"vscode-docker.commands.registries.disconnectRegistry": "Disconnect",
"vscode-docker.commands.registries.genericV2.removeTrackedRegistry": "Disconnect from Generic Docker Registry",
"vscode-docker.commands.registries.genericV2.addTrackedRegistry": "Connect to Generic Docker Registry...",
"vscode-docker.commands.registries.dockerHub.openInBrowser": "Open in Browser",
"vscode-docker.commands.registries.help": "Registries Help",
"vscode-docker.commands.registries.logInToDockerCli": "Log In to Docker CLI",
@ -294,6 +293,7 @@
"vscode-docker.commands.contexts.configureExplorer": "Configure Explorer...",
"vscode-docker.commands.contexts.refresh": "Refresh",
"vscode-docker.commands.contexts.help": "Docker Context Help",
"vscode-docker.commands.activateRegistryProviders": "Activate Registry Providers...",
"vscode-docker.commands.category.docker": "Docker",
"vscode-docker.commands.category.dockerContainers": "Docker Containers",
"vscode-docker.commands.category.dockerImages": "Docker Images",

Просмотреть файл

@ -23,7 +23,11 @@ USER appuser
{{/if}}
{{/if}}
{{/unless}}
{{#if (eq netCorePlatformOS 'Windows')}}
FROM {{ netCoreSdkBaseImage }} AS build
{{else}}
FROM --platform=$BUILDPLATFORM {{ netCoreSdkBaseImage }} AS build
{{/if}}
ARG configuration=Release
WORKDIR /src
COPY ["{{ workspaceRelative . artifact }}", "{{ dirname (workspaceRelative . artifact) }}/"]

Просмотреть файл

@ -3,9 +3,11 @@
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DockerExtensionApi as DockerExtensionRegistryApi, RegistryDataProvider, RegistryItem } from '@microsoft/vscode-docker-registries';
import * as vscode from 'vscode';
import { ext } from './extensionVariables';
export class DockerExtensionApi implements MementoExplorerExport {
export class DockerExtensionApi implements MementoExplorerExport, DockerExtensionRegistryApi {
readonly #extensionMementos: ExtensionMementos | undefined;
public constructor(ctx: vscode.ExtensionContext) {
@ -18,6 +20,12 @@ export class DockerExtensionApi implements MementoExplorerExport {
}
}
public registerRegistryDataProvider<T extends RegistryItem>(id: string, registryDataProvider: RegistryDataProvider<T>): vscode.Disposable {
const disposable = ext.registriesTree.registerProvider(registryDataProvider);
void ext.registriesTree.refresh();
return disposable;
}
public get memento(): ExtensionMementos | undefined {
return this.#extensionMementos;
}

Просмотреть файл

@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import { IActionContext } from '@microsoft/vscode-azext-utils';
import { ContainerOS, VoidCommandResponse } from '@microsoft/vscode-container-client';
import { l10n } from 'vscode';
import { ext } from '../../extensionVariables';
import { ContainerOS, VoidCommandResponse } from '../../runtimes/docker';
import { TaskCommandRunnerFactory } from '../../runtimes/runners/TaskCommandRunnerFactory';
import { ContainerTreeItem } from '../../tree/containers/ContainerTreeItem';
import { getDockerOSType } from '../../utils/osUtils';

Просмотреть файл

@ -3,8 +3,8 @@
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { PortBinding } from '../../runtimes/docker';
import { IActionContext, IAzureQuickPickItem, TelemetryProperties } from '@microsoft/vscode-azext-utils';
import { PortBinding } from '@microsoft/vscode-container-client';
import * as vscode from 'vscode';
import { ext } from "../../extensionVariables";
import { ContainerTreeItem } from "../../tree/containers/ContainerTreeItem";

Просмотреть файл

@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import { IActionContext } from '@microsoft/vscode-azext-utils';
import { CommonOrchestratorCommandOptions, IContainerOrchestratorClient, LogsCommandOptions, VoidCommandResponse } from '@microsoft/vscode-container-client';
import * as path from 'path';
import { l10n } from 'vscode';
import { ext } from '../../extensionVariables';
import { CommonOrchestratorCommandOptions, IContainerOrchestratorClient, LogsCommandOptions, VoidCommandResponse } from '../../runtimes/docker';
import { TaskCommandRunnerFactory } from '../../runtimes/runners/TaskCommandRunnerFactory';
import { ContainerGroupTreeItem } from '../../tree/containers/ContainerGroupTreeItem';
import { ContainerTreeItem } from '../../tree/containers/ContainerTreeItem';

Просмотреть файл

@ -4,12 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import { IActionContext, NoResourceFoundError } from '@microsoft/vscode-azext-utils';
import { parseDockerLikeImageName } from '@microsoft/vscode-container-client';
import { CommonRegistry } from '@microsoft/vscode-docker-registries';
import * as vscode from 'vscode';
import { ext } from '../../extensionVariables';
import { TaskCommandRunnerFactory } from '../../runtimes/runners/TaskCommandRunnerFactory';
import { ImageTreeItem } from '../../tree/images/ImageTreeItem';
import { registryExpectedContextValues } from '../../tree/registries/registryContextValues';
import { RegistryTreeItemBase } from '../../tree/registries/RegistryTreeItemBase';
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
import { registryExperience } from '../../utils/registryExperience';
import { addImageTaggingTelemetry, tagImage } from './tagImage';
export async function pushImage(context: IActionContext, node: ImageTreeItem | undefined): Promise<void> {
@ -21,7 +23,7 @@ export async function pushImage(context: IActionContext, node: ImageTreeItem | u
});
}
let connectedRegistry: RegistryTreeItemBase | undefined;
let connectedRegistry: UnifiedRegistryItem<CommonRegistry> | undefined;
if (!node.fullTag.includes('/')) {
// The registry to push to is indeterminate--could be Docker Hub, or could need tagging.
@ -30,7 +32,7 @@ export async function pushImage(context: IActionContext, node: ImageTreeItem | u
// If the prompt setting is true, we'll ask; if not we'll assume Docker Hub.
if (prompt) {
try {
connectedRegistry = await ext.registriesTree.showTreeItemPicker<RegistryTreeItemBase>(registryExpectedContextValues.all.registry, context);
connectedRegistry = await registryExperience<CommonRegistry>(context, { contextValueFilter: { include: [/commonregistry/i] } });
} catch (error) {
if (error instanceof NoResourceFoundError) {
// Do nothing, move on without a selected registry
@ -41,25 +43,30 @@ export async function pushImage(context: IActionContext, node: ImageTreeItem | u
}
} else {
// Try to find a connected Docker Hub registry (primarily for login credentials)
connectedRegistry = await tryGetDockerHubRegistry(context);
connectedRegistry = await registryExperience<CommonRegistry>(
context,
{
registryFilter: { include: [ext.dockerHubRegistryDataProvider.label] },
contextValueFilter: { include: /commonregistry/i },
skipIfOne: true
}
);
}
} else {
// The registry to push to is determinate. If there's a connected registry in the tree view, we'll try to find it, to perform login ahead of time.
// Registry path is everything up to the last slash.
const baseImagePath = node.fullTag.substring(0, node.fullTag.lastIndexOf('/'));
const progressOptions: vscode.ProgressOptions = {
location: vscode.ProgressLocation.Notification,
title: vscode.l10n.t('Fetching login credentials...'),
};
connectedRegistry = await vscode.window.withProgress(progressOptions, async () => await tryGetConnectedRegistryForPath(context, baseImagePath));
connectedRegistry = await vscode.window.withProgress(progressOptions, async () => await tryGetConnectedRegistryForPath(context, node.parent.label));
}
// Give the user a chance to modify the tag however they want
const finalTag = await tagImage(context, node, connectedRegistry);
if (connectedRegistry && finalTag.startsWith(connectedRegistry.baseImagePath)) {
const baseImagePath = connectedRegistry.wrappedItem.baseUrl.authority;
if (connectedRegistry && finalTag.startsWith(baseImagePath)) {
// If a registry was found/chosen and is still the same as the final tag's registry, try logging in
await vscode.commands.executeCommand('vscode-docker.registries.logInToDockerCli', connectedRegistry);
}
@ -78,12 +85,15 @@ export async function pushImage(context: IActionContext, node: ImageTreeItem | u
);
}
async function tryGetConnectedRegistryForPath(context: IActionContext, baseImagePath: string): Promise<RegistryTreeItemBase | undefined> {
const allRegistries = await ext.registriesRoot.getAllConnectedRegistries(context);
return allRegistries.find(r => r.baseImagePath === baseImagePath);
}
async function tryGetConnectedRegistryForPath(context: IActionContext, baseImagePath: string): Promise<UnifiedRegistryItem<CommonRegistry> | undefined> {
const baseImageNameInfo = parseDockerLikeImageName(baseImagePath);
const allRegistries = await ext.registriesTree.getConnectedRegistries(baseImageNameInfo.registry);
async function tryGetDockerHubRegistry(context: IActionContext): Promise<RegistryTreeItemBase | undefined> {
const allRegistries = await ext.registriesRoot.getAllConnectedRegistries(context);
return allRegistries.find(r => r.contextValue.match(registryExpectedContextValues.dockerHub.registry));
let matchedRegistry = allRegistries.find((registry) => registry.wrappedItem.baseUrl.authority === baseImageNameInfo.registry);
if (!matchedRegistry) {
matchedRegistry = await registryExperience<CommonRegistry>(context, { contextValueFilter: { include: [/commonregistry/i] } });
}
return matchedRegistry;
}

Просмотреть файл

@ -4,13 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import { DialogResponses, IActionContext } from '@microsoft/vscode-azext-utils';
import { RunContainerBindMount } from '@microsoft/vscode-container-client';
import * as fse from 'fs-extra';
import * as os from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import { l10n } from 'vscode';
import { ext } from '../../extensionVariables';
import { RunContainerBindMount } from '../../runtimes/docker';
import { TaskCommandRunnerFactory } from '../../runtimes/runners/TaskCommandRunnerFactory';
import { getDockerOSType } from '../../utils/osUtils';

Просмотреть файл

@ -4,12 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import { IActionContext, TelemetryProperties } from '@microsoft/vscode-azext-utils';
import { CommonRegistry, isRegistry } from '@microsoft/vscode-docker-registries';
import * as vscode from 'vscode';
import { ext } from '../../extensionVariables';
import { ImageTreeItem } from '../../tree/images/ImageTreeItem';
import { RegistryTreeItemBase } from '../../tree/registries/RegistryTreeItemBase';
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
import { getBaseImagePathFromRegistry } from '../../tree/registries/registryTreeUtils';
export async function tagImage(context: IActionContext, node?: ImageTreeItem, registry?: RegistryTreeItemBase): Promise<string> {
export async function tagImage(context: IActionContext, node?: ImageTreeItem, registry?: UnifiedRegistryItem<CommonRegistry>): Promise<string> {
if (!node) {
await ext.imagesTree.refresh(context);
node = await ext.imagesTree.showTreeItemPicker<ImageTreeItem>(ImageTreeItem.contextValue, {
@ -19,7 +21,8 @@ export async function tagImage(context: IActionContext, node?: ImageTreeItem, re
}
addImageTaggingTelemetry(context, node.fullTag, '.before');
const newTaggedName: string = await getTagFromUserInput(context, node.fullTag, registry?.baseImagePath);
const baseImagePath = isRegistry(registry?.wrappedItem) ? getBaseImagePathFromRegistry(registry.wrappedItem) : undefined;
const newTaggedName: string = await getTagFromUserInput(context, node.fullTag, baseImagePath);
addImageTaggingTelemetry(context, newTaggedName, '.after');
await ext.runWithDefaults(client =>

Просмотреть файл

@ -58,17 +58,16 @@ import { deployImageToAca } from "./registries/azure/deployImageToAca";
import { deployImageToAzure } from "./registries/azure/deployImageToAzure";
import { openInAzurePortal } from "./registries/azure/openInAzurePortal";
import { buildImageInAzure } from "./registries/azure/tasks/buildImageInAzure";
import { runAzureTask } from "./registries/azure/tasks/runAzureTask";
import { runFileAsAzureTask } from "./registries/azure/tasks/runFileAsAzureTask";
import { viewAzureTaskLogs } from "./registries/azure/tasks/viewAzureTaskLogs";
import { untagAzureImage } from "./registries/azure/untagAzureImage";
import { viewAzureProperties } from "./registries/azure/viewAzureProperties";
import { connectRegistry } from "./registries/connectRegistry";
import { copyRemoteFullTag } from './registries/copyRemoteFullTag';
import { copyRemoteFullTag } from "./registries/copyRemoteFullTag";
import { copyRemoteImageDigest } from "./registries/copyRemoteImageDigest";
import { deleteRemoteImage } from "./registries/deleteRemoteImage";
import { disconnectRegistry } from "./registries/disconnectRegistry";
import { openDockerHubInBrowser } from "./registries/dockerHub/openDockerHubInBrowser";
import { addTrackedGenericV2Registry } from "./registries/genericV2/addTrackedGenericV2Registry";
import { removeTrackedGenericV2Registry } from "./registries/genericV2/removeTrackedGenericV2Registry";
import { logInToDockerCli } from "./registries/logInToDockerCli";
import { logOutOfDockerCli } from "./registries/logOutOfDockerCli";
import { pullImageFromRepository, pullRepository } from "./registries/pullImages";
@ -180,6 +179,9 @@ export function registerCommands(): void {
registerWorkspaceCommand('vscode-docker.registries.pullRepository', pullRepository);
registerCommand('vscode-docker.registries.reconnectRegistry', reconnectRegistry);
registerCommand('vscode-docker.registries.genericV2.removeTrackedRegistry', removeTrackedGenericV2Registry);
registerCommand('vscode-docker.registries.genericV2.addTrackedRegistry', addTrackedGenericV2Registry);
registerCommand('vscode-docker.registries.dockerHub.openInBrowser', openDockerHubInBrowser);
registerWorkspaceCommand('vscode-docker.registries.azure.buildImage', buildImageInAzure);
@ -187,12 +189,9 @@ export function registerCommands(): void {
registerCommand('vscode-docker.registries.azure.deleteRegistry', deleteAzureRegistry);
registerCommand('vscode-docker.registries.azure.deleteRepository', deleteAzureRepository);
registerCommand('vscode-docker.registries.azure.openInPortal', openInAzurePortal);
registerCommand('vscode-docker.registries.azure.runTask', runAzureTask);
registerWorkspaceCommand('vscode-docker.registries.azure.runFileAsTask', runFileAsAzureTask);
registerCommand('vscode-docker.registries.azure.selectSubscriptions', () => commands.executeCommand("azure-account.selectSubscriptions"));
registerCommand('vscode-docker.registries.azure.untagImage', untagAzureImage);
registerCommand('vscode-docker.registries.azure.viewProperties', viewAzureProperties);
registerCommand('vscode-docker.registries.azure.viewTaskLogs', viewAzureTaskLogs);
registerCommand('vscode-docker.volumes.configureExplorer', configureVolumesExplorer);
registerCommand('vscode-docker.volumes.inspect', inspectVolume);
@ -208,4 +207,10 @@ export function registerCommands(): void {
registerCommand('vscode-docker.openDockerDownloadPage', openDockerDownloadPage);
registerCommand('vscode-docker.help', help);
registerCommand('vscode-docker.help.openWalkthrough', () => commands.executeCommand('workbench.action.openWalkthrough', 'ms-azuretools.vscode-docker#dockerStart'));
registerCommand('vscode-docker.activateRegistryProviders', (context: IActionContext) => {
// Do nothing, but registry provider extensions can use this command as an activation event
context.telemetry.suppressAll = true;
context.errorHandling.suppressDisplay = true;
});
}

Просмотреть файл

@ -5,17 +5,19 @@
import type { IAppServiceWizardContext } from "@microsoft/vscode-azext-azureappservice"; // These are only dev-time imports so don't need to be lazy
import { AzureWizardExecuteStep } from "@microsoft/vscode-azext-utils";
import { CommonTag } from "@microsoft/vscode-docker-registries";
import { randomUUID } from "crypto";
import { l10n, Progress } from "vscode";
import { Progress, l10n } from "vscode";
import { ext } from "../../../extensionVariables";
import { AzureRegistryTreeItem } from '../../../tree/registries/azure/AzureRegistryTreeItem';
import { RemoteTagTreeItem } from '../../../tree/registries/RemoteTagTreeItem';
import { AzureRegistry, isAzureTag } from "../../../tree/registries/Azure/AzureRegistryDataProvider";
import { UnifiedRegistryItem } from "../../../tree/registries/UnifiedRegistryTreeDataProvider";
import { getFullImageNameFromRegistryTagItem, getResourceGroupFromAzureRegistryItem } from "../../../tree/registries/registryTreeUtils";
import { getArmAuth, getArmContainerRegistry, getAzExtAppService, getAzExtAzureUtils } from "../../../utils/lazyPackages";
export class DockerAssignAcrPullRoleStep extends AzureWizardExecuteStep<IAppServiceWizardContext> {
public priority: number = 141; // execute after DockerSiteCreateStep
public constructor(private readonly tagTreeItem: RemoteTagTreeItem) {
public constructor(private readonly tagTreeItem: UnifiedRegistryItem<CommonTag>) {
super();
}
@ -33,14 +35,14 @@ export class DockerAssignAcrPullRoleStep extends AzureWizardExecuteStep<IAppServ
const appSvcClient = await vscAzureAppService.createWebSiteClient(context);
// If we're in `execute`, then `shouldExecute` passed and `this.tagTreeItem.parent.parent` is guaranteed to be an AzureRegistryTreeItem
const registryTreeItem: AzureRegistryTreeItem = this.tagTreeItem.parent.parent as unknown as AzureRegistryTreeItem;
const registryTreeItem: UnifiedRegistryItem<AzureRegistry> = this.tagTreeItem.parent.parent as unknown as UnifiedRegistryItem<AzureRegistry>;
// 1. Get the registry resource. We will need the ID.
const registry = await crmClient.registries.get(registryTreeItem.resourceGroup, registryTreeItem.registryName);
const registry = await crmClient.registries.get(getResourceGroupFromAzureRegistryItem(registryTreeItem.wrappedItem), registryTreeItem.wrappedItem.label);
if (!(registry?.id)) {
throw new Error(
l10n.t('Unable to get details from Container Registry {0}', registryTreeItem.baseUrl)
l10n.t('Unable to get details from Container Registry {0}', registryTreeItem.wrappedItem.label)
);
}
@ -78,12 +80,12 @@ export class DockerAssignAcrPullRoleStep extends AzureWizardExecuteStep<IAppServ
);
}
config.linuxFxVersion = `DOCKER|${this.tagTreeItem.fullTag}`;
const fullTag = getFullImageNameFromRegistryTagItem(this.tagTreeItem.wrappedItem);
config.linuxFxVersion = `DOCKER|${fullTag}`;
await appSvcClient.webApps.updateConfiguration(context.site.resourceGroup, context.site.name, config);
}
public shouldExecute(context: IAppServiceWizardContext): boolean {
return !!(context.site) && !!(this.tagTreeItem?.parent?.parent) && this.tagTreeItem.parent.parent instanceof AzureRegistryTreeItem
&& !context.customLocation;
return !!(context.site) && isAzureTag(this.tagTreeItem.wrappedItem) && !context.customLocation;
}
}

Просмотреть файл

@ -7,22 +7,19 @@ import type { NameValuePair, Site, SiteConfig, WebSiteManagementClient } from '@
import type { CustomLocation } from "@microsoft/vscode-azext-azureappservice"; // These are only dev-time imports so don't need to be lazy
import type { AzExtLocation } from '@microsoft/vscode-azext-azureutils'; // These are only dev-time imports so don't need to be lazy
import { AzureWizardExecuteStep, nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils";
import { l10n, Progress } from "vscode";
import { CommonRegistry, CommonTag } from '@microsoft/vscode-docker-registries';
import { Progress, l10n } from "vscode";
import { ext } from "../../../extensionVariables";
import { AzureRegistryTreeItem } from '../../../tree/registries/azure/AzureRegistryTreeItem';
import { DockerHubNamespaceTreeItem } from '../../../tree/registries/dockerHub/DockerHubNamespaceTreeItem';
import { DockerV2RegistryTreeItemBase } from '../../../tree/registries/dockerV2/DockerV2RegistryTreeItemBase';
import { GenericDockerV2RegistryTreeItem } from '../../../tree/registries/dockerV2/GenericDockerV2RegistryTreeItem';
import { getRegistryPassword } from '../../../tree/registries/registryPasswords';
import { RegistryTreeItemBase } from '../../../tree/registries/RegistryTreeItemBase';
import { RemoteTagTreeItem } from '../../../tree/registries/RemoteTagTreeItem';
import { AzureRegistryDataProvider, isAzureRegistry } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
import { getFullImageNameFromRegistryTagItem } from '../../../tree/registries/registryTreeUtils';
import { getAzExtAppService, getAzExtAzureUtils } from '../../../utils/lazyPackages';
import { IAppServiceContainerWizardContext } from './deployImageToAzure';
export class DockerSiteCreateStep extends AzureWizardExecuteStep<IAppServiceContainerWizardContext> {
public priority: number = 140;
public constructor(private readonly node: RemoteTagTreeItem) {
public constructor(private readonly tagItem: UnifiedRegistryItem<CommonTag>) {
super();
}
@ -49,7 +46,7 @@ export class DockerSiteCreateStep extends AzureWizardExecuteStep<IAppServiceCont
if (context.customLocation) {
// deploying to Azure Arc
siteEnvelope.kind = 'app,linux,kubernetes,container';
await this.addCustomLocationProperties(siteEnvelope, context.customLocation);
this.addCustomLocationProperties(siteEnvelope, context.customLocation);
} else {
siteEnvelope.identity = {
type: 'SystemAssigned'
@ -60,7 +57,7 @@ export class DockerSiteCreateStep extends AzureWizardExecuteStep<IAppServiceCont
}
private async getNewSiteConfig(context: IAppServiceContainerWizardContext): Promise<SiteConfig> {
const registryTI: RegistryTreeItemBase = this.node.parent.parent;
const registryTI: UnifiedRegistryItem<CommonRegistry> = this.tagItem.parent.parent as unknown as UnifiedRegistryItem<CommonRegistry>;
let username: string | undefined;
let password: string | undefined;
@ -69,7 +66,7 @@ export class DockerSiteCreateStep extends AzureWizardExecuteStep<IAppServiceCont
// Scenarios:
// ACR -> App Service, NOT Arc App Service. Use managed service identity.
if (registryTI instanceof AzureRegistryTreeItem && !context.customLocation) {
if (isAzureRegistry(registryTI.wrappedItem) && !context.customLocation) {
appSettings.push({ name: 'DOCKER_ENABLE_CI', value: 'true' });
// Don't need an image, username, or password--just create an empty web app to assign permissions and then configure with an image
@ -80,36 +77,29 @@ export class DockerSiteCreateStep extends AzureWizardExecuteStep<IAppServiceCont
};
}
// ACR -> Arc App Service. Use regular auth. Same as any V2 registry but different way of getting auth.
else if (registryTI instanceof AzureRegistryTreeItem && context.customLocation) {
const cred = await registryTI.tryGetAdminCredentials(context);
else if (isAzureRegistry(registryTI.wrappedItem) && context.customLocation) {
const cred = await (registryTI.provider as unknown as AzureRegistryDataProvider).tryGetAdminCredentials(registryTI.wrappedItem);
if (!cred?.username || !cred?.passwords?.[0]?.value) {
throw new Error(l10n.t('Azure App service deployment on Azure Arc only supports running images from Azure Container Registries with admin enabled'));
}
username = cred.username;
password = cred.passwords[0].value;
registryUrl = registryTI.baseUrl;
registryUrl = registryTI.wrappedItem.baseUrl.toString();
}
// Docker Hub -> App Service *OR* Arc App Service
else if (registryTI instanceof DockerHubNamespaceTreeItem) {
username = registryTI.parent.username;
password = await registryTI.parent.getPassword();
registryUrl = 'https://index.docker.io';
}
// Generic registry -> App Service *OR* Arc App Service
else if (registryTI instanceof DockerV2RegistryTreeItemBase) {
if (registryTI instanceof GenericDockerV2RegistryTreeItem) {
username = registryTI.cachedProvider.username;
password = await getRegistryPassword(registryTI.cachedProvider);
} else {
throw new RangeError(l10n.t('Unrecognized node type "{0}"', registryTI.constructor.name));
// Other registries -> App Service *OR* Arc App Service
else {
if (!registryTI.provider.getLoginInformation) {
throw new Error(l10n.t('This registry does not support deploying to Azure App Service'));
}
const loginInformation = await registryTI.provider.getLoginInformation(registryTI.wrappedItem);
registryUrl = registryTI.baseUrl;
} else {
throw new RangeError(l10n.t('Unrecognized node type "{0}"', registryTI.constructor.name));
registryUrl = (registryTI.wrappedItem as CommonRegistry).baseUrl.toString();
username = loginInformation.username;
password = loginInformation.secret;
}
if (username && password) {
appSettings.push({ name: "DOCKER_REGISTRY_SERVER_USERNAME", value: username });
appSettings.push({ name: "DOCKER_REGISTRY_SERVER_PASSWORD", value: password });
@ -123,7 +113,7 @@ export class DockerSiteCreateStep extends AzureWizardExecuteStep<IAppServiceCont
appSettings.push({ name: "WEBSITES_PORT", value: context.webSitesPort.toString() });
}
const linuxFxVersion = `DOCKER|${this.node.fullTag}`;
const linuxFxVersion = `DOCKER|${getFullImageNameFromRegistryTagItem(this.tagItem.wrappedItem)}`;
return {
linuxFxVersion,

Просмотреть файл

@ -7,21 +7,20 @@ import type { Site } from '@azure/arm-appservice'; // These are only dev-time im
import type { Webhook, WebhookCreateParameters } from '@azure/arm-containerregistry'; // These are only dev-time imports so don't need to be lazy
import type { IAppServiceWizardContext } from "@microsoft/vscode-azext-azureappservice"; // These are only dev-time imports so don't need to be lazy
import { AzureWizardExecuteStep, nonNullProp } from "@microsoft/vscode-azext-utils";
import { CommonRepository, CommonTag, isDockerHubRepository } from '@microsoft/vscode-docker-registries';
import * as vscode from "vscode";
import { ext } from "../../../extensionVariables";
import { AzureRegistryTreeItem } from '../../../tree/registries/azure/AzureRegistryTreeItem';
import { AzureRepositoryTreeItem } from '../../../tree/registries/azure/AzureRepositoryTreeItem';
import { DockerHubRepositoryTreeItem } from '../../../tree/registries/dockerHub/DockerHubRepositoryTreeItem';
import { RemoteTagTreeItem } from '../../../tree/registries/RemoteTagTreeItem';
import { AzureRegistry, isAzureRepository } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
import { getResourceGroupFromAzureRegistryItem } from '../../../tree/registries/registryTreeUtils';
import { cryptoUtils } from '../../../utils/cryptoUtils';
import { getArmContainerRegistry, getAzExtAppService, getAzExtAzureUtils } from "../../../utils/lazyPackages";
export class DockerWebhookCreateStep extends AzureWizardExecuteStep<IAppServiceWizardContext> {
public priority: number = 142; // execute after DockerAssignAcrPullRoleStep
private _treeItem: RemoteTagTreeItem;
public constructor(treeItem: RemoteTagTreeItem) {
public constructor(private readonly tagItem: UnifiedRegistryItem<CommonTag>) {
super();
this._treeItem = treeItem;
}
public async execute(context: IAppServiceWizardContext, progress: vscode.Progress<{
@ -34,17 +33,20 @@ export class DockerWebhookCreateStep extends AzureWizardExecuteStep<IAppServiceW
const parsedSite = new vscAzureAppService.ParsedSite(site, context);
const siteClient = await parsedSite.createClient(context);
const appUri: string = (await siteClient.getWebAppPublishCredential()).scmUri;
if (this._treeItem.parent instanceof AzureRepositoryTreeItem) {
if (isAzureRepository(this.tagItem.parent.wrappedItem)) {
const creatingNewWebhook: string = vscode.l10n.t('Creating webhook for web app "{0}"...', context.newSiteName);
ext.outputChannel.info(creatingNewWebhook);
progress.report({ message: creatingNewWebhook });
const webhook = await this.createWebhookForApp(context, this._treeItem, context.site, appUri);
const webhook = await this.createWebhookForApp(context, context.site, appUri);
ext.outputChannel.info(vscode.l10n.t('Created webhook "{0}" with scope "{1}", id: "{2}" and location: "{3}"', webhook.name, webhook.scope, webhook.id, webhook.location));
} else if (this._treeItem.parent instanceof DockerHubRepositoryTreeItem) {
} else if (isDockerHubRepository(this.tagItem.parent.wrappedItem)) {
const registryName = this.tagItem.parent.parent.wrappedItem.label;
const repoName = (this.tagItem.parent as unknown as CommonRepository).wrappedItem.label;
// point to dockerhub to create a webhook
// http://cloud.docker.com/repository/docker/<registryName>/<repoName>/webHooks
const dockerhubPrompt: string = vscode.l10n.t('Copy & Open');
const dockerhubUri: string = `https://cloud.docker.com/repository/docker/${this._treeItem.parent.parent.namespace}/${this._treeItem.parent.repoName}/webHooks`;
const dockerhubUri: string = `https://cloud.docker.com/repository/docker/${registryName}/${repoName}/webHooks`;
// NOTE: The response to the information message is not awaited but handled independently of the wizard steps.
// VS Code will hide such messages in the notifications pane after a period of time; awaiting them risks
@ -64,10 +66,10 @@ export class DockerWebhookCreateStep extends AzureWizardExecuteStep<IAppServiceW
}
public shouldExecute(context: IAppServiceWizardContext): boolean {
return !!context.site && (this._treeItem.parent instanceof AzureRepositoryTreeItem || this._treeItem.parent instanceof DockerHubRepositoryTreeItem);
return !!context.site && (isAzureRepository(this.tagItem.parent.wrappedItem) || isDockerHubRepository(this.tagItem.parent.wrappedItem));
}
private async createWebhookForApp(context: IAppServiceWizardContext, node: RemoteTagTreeItem, site: Site, appUri: string): Promise<Webhook | undefined> {
private async createWebhookForApp(context: IAppServiceWizardContext, site: Site, appUri: string): Promise<Webhook | undefined> {
const maxLength: number = 50;
const numRandomChars: number = 6;
@ -80,17 +82,18 @@ export class DockerWebhookCreateStep extends AzureWizardExecuteStep<IAppServiceW
webhookName += cryptoUtils.getRandomHexString(numRandomChars);
// variables derived from the container registry
const registryTreeItem: AzureRegistryTreeItem = (<AzureRepositoryTreeItem>node.parent).parent;
const registryTreeItem: UnifiedRegistryItem<AzureRegistry> = this.tagItem.parent.parent as unknown as UnifiedRegistryItem<AzureRegistry>;
const armContainerRegistry = await getArmContainerRegistry();
const azExtAzureUtils = await getAzExtAzureUtils();
const crmClient = azExtAzureUtils.createAzureClient(context, armContainerRegistry.ContainerRegistryManagementClient);
const webhookCreateParameters: WebhookCreateParameters = {
location: registryTreeItem.registryLocation,
location: registryTreeItem.wrappedItem.registryProperties.location,
serviceUri: appUri,
scope: `${node.parent.repoName}:${node.tag}`,
scope: `${this.tagItem.parent.wrappedItem.label}:${this.tagItem.wrappedItem.label}`,
actions: ["push"],
status: 'enabled'
};
return await crmClient.webhooks.beginCreateAndWait(registryTreeItem.resourceGroup, registryTreeItem.registryName, webhookName, webhookCreateParameters);
const resourceGroup = getResourceGroupFromAzureRegistryItem(registryTreeItem.wrappedItem);
return await crmClient.webhooks.beginCreateAndWait(resourceGroup, registryTreeItem.wrappedItem.label, webhookName, webhookCreateParameters);
}
}

Просмотреть файл

@ -3,17 +3,61 @@
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IActionContext } from '@microsoft/vscode-azext-utils';
import { AzureWizard, IActionContext, createSubscriptionContext, nonNullProp } from '@microsoft/vscode-azext-utils';
import { l10n, window } from 'vscode';
import { ext } from '../../../extensionVariables';
import type { SubscriptionTreeItem } from '../../../tree/registries/azure/SubscriptionTreeItem'; // These are only dev-time imports so don't need to be lazy
import { getAzSubTreeItem } from '../../../utils/lazyPackages';
import { AzureSubscriptionRegistryItem } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
import { AzureRegistryCreateStep } from '../../../tree/registries/Azure/createWizard/AzureRegistryCreateStep';
import { AzureRegistryNameStep } from '../../../tree/registries/Azure/createWizard/AzureRegistryNameStep';
import { AzureRegistrySkuStep } from '../../../tree/registries/Azure/createWizard/AzureRegistrySkuStep';
import { IAzureRegistryWizardContext } from '../../../tree/registries/Azure/createWizard/IAzureRegistryWizardContext';
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
import { getAzExtAzureUtils } from '../../../utils/lazyPackages';
import { registryExperience } from '../../../utils/registryExperience';
export async function createAzureRegistry(context: IActionContext, node?: SubscriptionTreeItem): Promise<void> {
const azSubTreeItem = await getAzSubTreeItem();
export async function createAzureRegistry(context: IActionContext, node?: UnifiedRegistryItem<AzureSubscriptionRegistryItem>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<SubscriptionTreeItem>(azSubTreeItem.SubscriptionTreeItem.contextValue, context);
node = await registryExperience<AzureSubscriptionRegistryItem>(context,
{
contextValueFilter: { include: /azuresubscription/i },
registryFilter: { include: [ext.azureRegistryDataProvider.label] }
}
);
}
await node.createChild(context);
const registryItem = node.wrappedItem;
const subscriptionContext = createSubscriptionContext(registryItem.subscription);
const wizardContext: IAzureRegistryWizardContext = {
...context,
...subscriptionContext,
azureSubscription: registryItem.subscription,
};
const azExtAzureUtils = await getAzExtAzureUtils();
const promptSteps = [
new AzureRegistryNameStep(),
new AzureRegistrySkuStep(),
new azExtAzureUtils.ResourceGroupListStep(),
];
azExtAzureUtils.LocationListStep.addStep(wizardContext, promptSteps);
const wizard = new AzureWizard(
wizardContext,
{
promptSteps,
executeSteps: [
new AzureRegistryCreateStep()
],
title: l10n.t('Create new Azure Container Registry')
}
);
await wizard.prompt();
const newRegistryName: string = nonNullProp(wizardContext, 'newRegistryName');
await wizard.execute();
void window.showInformationMessage(`Successfully created registry "${newRegistryName}".`);
void ext.registriesTree.refresh();
}

Просмотреть файл

@ -4,26 +4,35 @@
*--------------------------------------------------------------------------------------------*/
import { DialogResponses, IActionContext } from '@microsoft/vscode-azext-utils';
import { l10n, ProgressLocation, window } from 'vscode';
import { ProgressLocation, l10n, window } from 'vscode';
import { ext } from '../../../extensionVariables';
import type { AzureRegistryTreeItem } from '../../../tree/registries/azure/AzureRegistryTreeItem';
import { registryExpectedContextValues } from '../../../tree/registries/registryContextValues';
import { AzureRegistry, AzureRegistryDataProvider } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
import { registryExperience } from '../../../utils/registryExperience';
export async function deleteAzureRegistry(context: IActionContext, node?: AzureRegistryTreeItem): Promise<void> {
export async function deleteAzureRegistry(context: IActionContext, node?: UnifiedRegistryItem<AzureRegistry>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<AzureRegistryTreeItem>(registryExpectedContextValues.azure.registry, { ...context, suppressCreatePick: true });
node = await registryExperience<AzureRegistry>(context, {
contextValueFilter: { include: /commonregistry/i },
registryFilter: { include: [ext.azureRegistryDataProvider.label] }
});
}
const confirmDelete: string = l10n.t('Are you sure you want to delete registry "{0}" and its associated images?', node.registryName);
const registryName = node.wrappedItem.label;
const confirmDelete: string = l10n.t('Are you sure you want to delete registry "{0}" and its associated images?', registryName);
// no need to check result - cancel will throw a UserCancelledError
await context.ui.showWarningMessage(confirmDelete, { modal: true }, DialogResponses.deleteResponse);
const deleting = l10n.t('Deleting registry "{0}"...', node.registryName);
const deleting = l10n.t('Deleting registry "{0}"...', registryName);
await window.withProgress({ location: ProgressLocation.Notification, title: deleting }, async () => {
await node.deleteTreeItem(context);
const azureRegistryDataProvider = node.provider as unknown as AzureRegistryDataProvider;
await azureRegistryDataProvider.deleteRegistry(node.wrappedItem);
});
const message = l10n.t('Successfully deleted registry "{0}".', node.registryName);
void ext.registriesTree.refresh();
const message = l10n.t('Successfully deleted registry "{0}".', registryName);
// don't wait
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
window.showInformationMessage(message);

Просмотреть файл

@ -4,27 +4,32 @@
*--------------------------------------------------------------------------------------------*/
import { DialogResponses, IActionContext } from '@microsoft/vscode-azext-utils';
import { l10n, ProgressLocation, window } from 'vscode';
import { ProgressLocation, l10n, window } from 'vscode';
import { ext } from '../../../extensionVariables';
import type { AzureRepositoryTreeItem } from '../../../tree/registries/azure/AzureRepositoryTreeItem';
import { registryExpectedContextValues } from '../../../tree/registries/registryContextValues';
import { AzureRegistryDataProvider, AzureRepository } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
import { registryExperience } from '../../../utils/registryExperience';
export async function deleteAzureRepository(context: IActionContext, node?: AzureRepositoryTreeItem): Promise<void> {
export async function deleteAzureRepository(context: IActionContext, node?: UnifiedRegistryItem<AzureRepository>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<AzureRepositoryTreeItem>(registryExpectedContextValues.azure.repository, { ...context, suppressCreatePick: true });
node = await registryExperience<AzureRepository>(context, {
contextValueFilter: { include: /commonrepository/i },
registryFilter: { include: [ext.azureRegistryDataProvider.label] }
});
}
const confirmDelete = l10n.t('Are you sure you want to delete repository "{0}" and its associated images?', node.repoName);
const confirmDelete = l10n.t('Are you sure you want to delete repository "{0}" and its associated images?', node.wrappedItem.label);
// no need to check result - cancel will throw a UserCancelledError
await context.ui.showWarningMessage(confirmDelete, { modal: true }, DialogResponses.deleteResponse);
const deleting = l10n.t('Deleting repository "{0}"...', node.repoName);
const deleting = l10n.t('Deleting repository "{0}"...', node.wrappedItem.label);
await window.withProgress({ location: ProgressLocation.Notification, title: deleting }, async () => {
await node.deleteTreeItem(context);
const azureDataProvider = node.provider as unknown as AzureRegistryDataProvider;
await azureDataProvider.deleteRepository(node.wrappedItem);
});
const deleteSucceeded = l10n.t('Successfully deleted repository "{0}".', node.repoName);
// don't wait
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
window.showInformationMessage(deleteSucceeded);
void ext.registriesTree.refresh();
const deleteSucceeded = l10n.t('Successfully deleted repository "{0}".', node.wrappedItem.label);
void window.showInformationMessage(deleteSucceeded);
}

Просмотреть файл

@ -4,16 +4,15 @@
*--------------------------------------------------------------------------------------------*/
import { IActionContext, nonNullProp, UserCancelledError } from '@microsoft/vscode-azext-utils';
import { parseDockerLikeImageName } from '@microsoft/vscode-container-client';
import { CommonRegistry, CommonTag, isDockerHubRegistry, LoginInformation } from '@microsoft/vscode-docker-registries';
import * as semver from 'semver';
import * as vscode from 'vscode';
import { ext } from '../../../extensionVariables';
import { parseDockerLikeImageName } from '../../../runtimes/docker/clients/DockerClientBase/parseDockerLikeImageName';
import { AzureRegistryTreeItem } from '../../../tree/registries/azure/AzureRegistryTreeItem';
import { DockerHubNamespaceTreeItem } from '../../../tree/registries/dockerHub/DockerHubNamespaceTreeItem';
import { registryExpectedContextValues } from '../../../tree/registries/registryContextValues';
import { RegistryTreeItemBase } from '../../../tree/registries/RegistryTreeItemBase';
import { RemoteTagTreeItem } from '../../../tree/registries/RemoteTagTreeItem';
import { isAzureRegistry } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
import { getFullImageNameFromRegistryTagItem } from '../../../tree/registries/registryTreeUtils';
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
import { installExtension } from '../../../utils/installExtension';
import { registryExperience } from '../../../utils/registryExperience';
import { addImageTaggingTelemetry } from '../../images/tagImage';
const acaExtensionId = 'ms-azuretools.vscode-azurecontainerapps';
@ -27,7 +26,7 @@ interface DeployImageToAcaOptionsContract {
secret?: string;
}
export async function deployImageToAca(context: IActionContext, node?: RemoteTagTreeItem): Promise<void> {
export async function deployImageToAca(context: IActionContext, node?: UnifiedRegistryItem<CommonTag>): Promise<void> {
// Assert installation of the ACA extension
if (!isAcaExtensionInstalled()) {
// This will always throw a `UserCancelledError` but with the appropriate step name
@ -36,34 +35,35 @@ export async function deployImageToAca(context: IActionContext, node?: RemoteTag
}
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<RemoteTagTreeItem>([registryExpectedContextValues.dockerHub.tag, registryExpectedContextValues.dockerV2.tag], context);
node = await registryExperience<CommonTag>(context, { contextValueFilter: { include: /commontag/i } });
}
const commandOptions: Partial<DeployImageToAcaOptionsContract> = {
image: node.fullTag,
image: getFullImageNameFromRegistryTagItem(node.wrappedItem),
};
addImageTaggingTelemetry(context, commandOptions.image, '');
const registry: RegistryTreeItemBase = node.parent.parent;
if (registry instanceof AzureRegistryTreeItem) {
const registry: UnifiedRegistryItem<CommonRegistry> = node.parent.parent as unknown as UnifiedRegistryItem<CommonRegistry>;
if (isAzureRegistry(registry.wrappedItem)) {
// No additional work to do; ACA can handle this on its own
} else {
const { auth } = await registry.getDockerCliCredentials() as { auth?: { username?: string, password?: string } };
const logInInfo: LoginInformation = await registry.provider.getLoginInformation(registry.wrappedItem);
if (!auth?.username || !auth?.password) {
throw new Error(vscode.l10n.t('No credentials found for registry "{0}".', registry.label));
if (!logInInfo?.username || !logInInfo?.secret) {
throw new Error(vscode.l10n.t('No credentials found for registry "{0}".', registry.wrappedItem.label));
}
if (registry instanceof DockerHubNamespaceTreeItem) {
if (isDockerHubRegistry(registry.wrappedItem)) {
// Ensure Docker Hub images are prefixed with 'docker.io/...'
if (!/^docker\.io\//i.test(commandOptions.image)) {
commandOptions.image = 'docker.io/' + commandOptions.image;
}
}
commandOptions.username = auth.username;
commandOptions.secret = auth.password;
commandOptions.username = logInInfo.username;
commandOptions.secret = logInInfo.secret;
}
commandOptions.registryName = nonNullProp(parseDockerLikeImageName(commandOptions.image), 'registry');

Просмотреть файл

@ -5,45 +5,43 @@
import type { Site } from '@azure/arm-appservice'; // These are only dev-time imports so don't need to be lazy
import type { IAppServiceWizardContext } from "@microsoft/vscode-azext-azureappservice"; // These are only dev-time imports so don't need to be lazy
import { AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, IActionContext, nonNullProp } from "@microsoft/vscode-azext-utils";
import { env, l10n, Uri, window } from "vscode";
import { AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, IActionContext, createSubscriptionContext, nonNullProp } from "@microsoft/vscode-azext-utils";
import { CommonTag } from '@microsoft/vscode-docker-registries';
import { Uri, env, l10n, window } from "vscode";
import { ext } from "../../../extensionVariables";
import { RegistryApi } from '../../../tree/registries/all/RegistryApi';
import { azureRegistryProviderId } from '../../../tree/registries/azure/azureRegistryProvider';
import { registryExpectedContextValues } from '../../../tree/registries/registryContextValues';
import { RemoteTagTreeItem } from '../../../tree/registries/RemoteTagTreeItem';
import { getAzActTreeItem, getAzExtAppService, getAzExtAzureUtils } from '../../../utils/lazyPackages';
import { AzureSubscriptionRegistryItem } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
import { getAzExtAppService, getAzExtAzureUtils } from '../../../utils/lazyPackages';
import { registryExperience } from '../../../utils/registryExperience';
import { DockerAssignAcrPullRoleStep } from './DockerAssignAcrPullRoleStep';
import { DockerSiteCreateStep } from './DockerSiteCreateStep';
import { DockerWebhookCreateStep } from './DockerWebhookCreateStep';
import { WebSitesPortPromptStep } from './WebSitesPortPromptStep';
export interface IAppServiceContainerWizardContext extends IAppServiceWizardContext {
webSitesPort?: number;
}
export async function deployImageToAzure(context: IActionContext, node?: RemoteTagTreeItem): Promise<void> {
export async function deployImageToAzure(context: IActionContext, node?: UnifiedRegistryItem<CommonTag>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<RemoteTagTreeItem>([registryExpectedContextValues.dockerHub.tag, registryExpectedContextValues.dockerV2.tag], context);
node = await registryExperience<CommonTag>(context, { contextValueFilter: { include: 'commontag' } });
}
const azExtAzureUtils = await getAzExtAzureUtils();
const vscAzureAppService = await getAzExtAppService();
const azActTreeItem = await getAzActTreeItem();
const promptSteps: AzureWizardPromptStep<IAppServiceWizardContext>[] = [];
const subscriptionItem = await registryExperience<AzureSubscriptionRegistryItem>(context, {
registryFilter: { include: [ext.azureRegistryDataProvider.label] },
contextValueFilter: { include: /azuresubscription/i },
});
const subscriptionContext = createSubscriptionContext(subscriptionItem.wrappedItem.subscription);
const wizardContext: IActionContext & Partial<IAppServiceContainerWizardContext> = {
...context,
...subscriptionContext,
newSiteOS: vscAzureAppService.WebsiteOS.linux,
newSiteKind: vscAzureAppService.AppKind.app
};
const promptSteps: AzureWizardPromptStep<IAppServiceWizardContext>[] = [];
// Create a temporary azure account tree item since Azure might not be connected
const azureAccountTreeItem = new azActTreeItem.AzureAccountTreeItem(ext.registriesRoot, { id: azureRegistryProviderId, api: RegistryApi.DockerV2 });
const subscriptionStep = await azureAccountTreeItem.getSubscriptionPromptStep(wizardContext);
if (subscriptionStep) {
promptSteps.push(subscriptionStep);
}
promptSteps.push(new vscAzureAppService.SiteNameStep());
promptSteps.push(new azExtAzureUtils.ResourceGroupListStep());

Просмотреть файл

@ -3,27 +3,32 @@
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IActionContext } from '@microsoft/vscode-azext-utils';
import { IActionContext, createSubscriptionContext } from '@microsoft/vscode-azext-utils';
import { ext } from '../../../extensionVariables';
import { AzureRegistryTreeItem } from '../../../tree/registries/azure/AzureRegistryTreeItem';
import { AzureRepositoryTreeItem } from '../../../tree/registries/azure/AzureRepositoryTreeItem';
import type { SubscriptionTreeItem } from '../../../tree/registries/azure/SubscriptionTreeItem'; // These are only dev-time imports so don't need to be lazy
import { registryExpectedContextValues } from '../../../tree/registries/registryContextValues';
import { getAzExtAzureUtils, getAzSubTreeItem } from '../../../utils/lazyPackages';
import { AzureRegistry, AzureRepository, AzureSubscriptionRegistryItem, isAzureRegistry, isAzureSubscriptionRegistryItem } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
import { getAzExtAzureUtils } from '../../../utils/lazyPackages';
import { registryExperience } from '../../../utils/registryExperience';
export async function openInAzurePortal(context: IActionContext, node?: SubscriptionTreeItem | AzureRegistryTreeItem | AzureRepositoryTreeItem): Promise<void> {
export async function openInAzurePortal(context: IActionContext, node?: UnifiedRegistryItem<AzureRegistry | AzureSubscriptionRegistryItem | AzureRepository>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<AzureRegistryTreeItem>(registryExpectedContextValues.azure.registry, context);
node = await registryExperience<AzureRegistry>(context, {
registryFilter: { include: [ext.azureRegistryDataProvider.label] },
contextValueFilter: { include: [/commonregistry/i] },
});
}
const azSubTreeItem = await getAzSubTreeItem();
const azureRegistryItem = node.wrappedItem;
const azExtAzureUtils = await getAzExtAzureUtils();
if (node instanceof azSubTreeItem.SubscriptionTreeItem) {
await azExtAzureUtils.openInPortal(node.subscription, node.subscription.subscriptionId);
} else if (node instanceof AzureRegistryTreeItem) {
await azExtAzureUtils.openInPortal(node.parent.subscription, node.registryId);
let subscriptionContext = undefined;
if (isAzureSubscriptionRegistryItem(azureRegistryItem)) {
subscriptionContext = createSubscriptionContext(azureRegistryItem.subscription);
await azExtAzureUtils.openInPortal(subscriptionContext, `/subscriptions/${subscriptionContext.subscriptionId}`);
} else if (isAzureRegistry(azureRegistryItem)) {
subscriptionContext = createSubscriptionContext(azureRegistryItem.parent.subscription);
await azExtAzureUtils.openInPortal(subscriptionContext, azureRegistryItem.id);
} else {
await azExtAzureUtils.openInPortal(node.parent.parent.subscription, `${node.parent.registryId}/repository`);
subscriptionContext = createSubscriptionContext(azureRegistryItem.parent.parent.subscription);
await azExtAzureUtils.openInPortal(subscriptionContext, `${azureRegistryItem.parent.id}/repository`);
}
}

Просмотреть файл

@ -3,12 +3,12 @@
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { IActionContext, UserCancelledError } from '@microsoft/vscode-azext-utils';
import type { Run } from '@azure/arm-containerregistry';
import { scheduleRunRequest, RootStrategy } from './scheduleRunRequest';
import { delay } from '../../../../utils/promiseUtils';
import { IActionContext, UserCancelledError } from '@microsoft/vscode-azext-utils';
import * as vscode from 'vscode';
import { getArmContainerRegistry } from '../../../../utils/lazyPackages';
import { delay } from '../../../../utils/promiseUtils';
import { RootStrategy, scheduleRunRequest } from './scheduleRunRequest';
const WAIT_MS = 5000;
@ -18,7 +18,7 @@ export async function buildImageInAzure(context: IActionContext, uri?: vscode.Ur
}
const getRun = await scheduleRunRequest(context, "DockerBuildRequest", uri, rootStrategy);
let run = await getRun();
const { KnownRunStatus } = await getArmContainerRegistry();
while (

Просмотреть файл

@ -1,24 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import type { TaskRunRequest } from "@azure/arm-containerregistry"; // These are only dev-time imports so don't need to be lazy
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { l10n, window } from "vscode";
import { ext } from "../../../../extensionVariables";
import { AzureTaskTreeItem } from "../../../../tree/registries/azure/AzureTaskTreeItem";
export async function runAzureTask(context: IActionContext, node?: AzureTaskTreeItem): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<AzureTaskTreeItem>(AzureTaskTreeItem.contextValue, context);
}
const registryTI = node.parent.parent;
const runRequest: TaskRunRequest = { type: 'TaskRunRequest', taskId: node.id };
const run = await (await registryTI.getClient(context)).registries.beginScheduleRunAndWait(registryTI.resourceGroup, registryTI.registryName, runRequest);
await node.parent.refresh(context);
// don't wait
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
window.showInformationMessage(l10n.t('Successfully scheduled run "{0}" for task "{1}".', run.runId, node.taskName));
}

Просмотреть файл

@ -1,16 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { IActionContext, UserCancelledError } from '@microsoft/vscode-azext-utils';
import { scheduleRunRequest } from './scheduleRunRequest';
export async function runFileAsAzureTask(context: IActionContext, uri?: vscode.Uri): Promise<void> {
if (!vscode.workspace.isTrusted) {
throw new UserCancelledError('enforceTrust');
}
await scheduleRunRequest(context, "FileTaskRunRequest", uri);
}

Просмотреть файл

@ -3,7 +3,7 @@
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import type { ContainerRegistryManagementClient, DockerBuildRequest as AcrDockerBuildRequest, FileTaskRunRequest as AcrFileTaskRunRequest, OS as AcrOS, Run as AcrRun } from "@azure/arm-containerregistry"; // These are only dev-time imports so don't need to be lazy
import type { DockerBuildRequest as AcrDockerBuildRequest, FileTaskRunRequest as AcrFileTaskRunRequest, OS as AcrOS, Run as AcrRun, ContainerRegistryManagementClient } from "@azure/arm-containerregistry"; // These are only dev-time imports so don't need to be lazy
import { IActionContext, IAzureQuickPickItem, nonNullProp } from '@microsoft/vscode-azext-utils';
import * as fse from 'fs-extra';
import * as os from 'os';
@ -12,12 +12,14 @@ import * as readline from 'readline';
import * as tar from 'tar';
import * as vscode from 'vscode';
import { ext } from '../../../../extensionVariables';
import { AzureRegistryTreeItem } from '../../../../tree/registries/azure/AzureRegistryTreeItem';
import { registryExpectedContextValues } from "../../../../tree/registries/registryContextValues";
import { AzureRegistry, AzureRegistryItem } from "../../../../tree/registries/Azure/AzureRegistryDataProvider";
import { UnifiedRegistryItem } from "../../../../tree/registries/UnifiedRegistryTreeDataProvider";
import { createAzureContainerRegistryClient, getResourceGroupFromId } from "../../../../utils/azureUtils";
import { getStorageBlob } from '../../../../utils/lazyPackages';
import { delay } from '../../../../utils/promiseUtils';
import { Item, quickPickDockerFileItem, quickPickYamlFileItem } from '../../../../utils/quickPickFile';
import { quickPickWorkspaceFolder } from '../../../../utils/quickPickWorkspaceFolder';
import { registryExperience } from "../../../../utils/registryExperience";
import { addImageTaggingTelemetry, getTagFromUserInput } from '../../../images/tagImage';
const idPrecision = 6;
@ -45,7 +47,12 @@ export async function scheduleRunRequest(context: IActionContext, requestType: '
throw new Error(vscode.l10n.t('Run Request Type Currently not supported.'));
}
const node = await ext.registriesTree.showTreeItemPicker<AzureRegistryTreeItem>(registryExpectedContextValues.azure.registry, context);
const node: UnifiedRegistryItem<AzureRegistryItem> = await registryExperience<AzureRegistry>(context, {
registryFilter: { include: [ext.azureRegistryDataProvider.label] },
contextValueFilter: { include: /commonregistry/i },
});
const registryItem: AzureRegistryItem = node.wrappedItem;
const resourceGroup = getResourceGroupFromId(registryItem.id);
const osPick = ['Linux', 'Windows'].map(item => <IAzureQuickPickItem<AcrOS>>{ label: item, data: item });
const osType: AcrOS = (await context.ui.showQuickPick(osPick, { placeHolder: vscode.l10n.t('Select image base OS') })).data;
@ -63,7 +70,8 @@ export async function scheduleRunRequest(context: IActionContext, requestType: '
rootUri = vscode.Uri.file(path.dirname(fileItem.absoluteFilePath));
}
const uploadedSourceLocation: string = await uploadSourceCode(await node.getClient(context), node.registryName, node.resourceGroup, rootUri, tarFilePath);
const azureRegistryClient = await createAzureContainerRegistryClient(registryItem.subscription);
const uploadedSourceLocation: string = await uploadSourceCode(azureRegistryClient, registryItem.label, resourceGroup, rootUri, tarFilePath);
ext.outputChannel.info(vscode.l10n.t('Uploaded source code from {0}', tarFilePath));
let runRequest: AcrDockerBuildRequest | AcrFileTaskRunRequest;
@ -88,14 +96,13 @@ export async function scheduleRunRequest(context: IActionContext, requestType: '
// Schedule the run and Clean up.
ext.outputChannel.info(vscode.l10n.t('Set up run request'));
const client = await node.getClient(context);
const run = await client.registries.beginScheduleRunAndWait(node.resourceGroup, node.registryName, runRequest);
const run = await azureRegistryClient.registries.beginScheduleRunAndWait(resourceGroup, registryItem.label, runRequest);
ext.outputChannel.info(vscode.l10n.t('Scheduled run {0}', run.runId));
void streamLogs(context, node, run);
void streamLogs(context, registryItem, run);
// function returns the AcrRun info
return async () => client.runs.get(node.resourceGroup, node.registryName, run.runId);
return async () => azureRegistryClient.runs.get(resourceGroup, registryItem.label, run.runId);
} finally {
if (await fse.pathExists(tarFilePath)) {
await fse.unlink(tarFilePath);
@ -155,8 +162,10 @@ async function uploadSourceCode(client: ContainerRegistryManagementClient, regis
const blobCheckInterval = 1000;
const maxBlobChecks = 30;
async function streamLogs(context: IActionContext, node: AzureRegistryTreeItem, run: AcrRun): Promise<void> {
const result = await (await node.getClient(context)).runs.getLogSasUrl(node.resourceGroup, node.registryName, run.runId);
async function streamLogs(context: IActionContext, registryItem: AzureRegistryItem, run: AcrRun): Promise<void> {
const azureRegistryClient = await createAzureContainerRegistryClient(registryItem.subscription);
const resourceGroup = getResourceGroupFromId(registryItem.id);
const result = await azureRegistryClient.runs.getLogSasUrl(resourceGroup, registryItem.label, run.runId);
const storageBlob = await getStorageBlob();
const blobClient = new storageBlob.BlobClient(nonNullProp(result, 'logLink'));

Просмотреть файл

@ -1,29 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IActionContext, nonNullProp, openReadOnlyContent } from "@microsoft/vscode-azext-utils";
import { l10n } from 'vscode';
import { ext } from "../../../../extensionVariables";
import { AzureTaskRunTreeItem } from "../../../../tree/registries/azure/AzureTaskRunTreeItem";
import { bufferToString } from "../../../../utils/execAsync";
import { getStorageBlob } from "../../../../utils/lazyPackages";
export async function viewAzureTaskLogs(context: IActionContext, node?: AzureTaskRunTreeItem): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<AzureTaskRunTreeItem>(AzureTaskRunTreeItem.contextValue, context);
}
const registryTI = node.parent.parent.parent;
await node.runWithTemporaryDescription(context, l10n.t('Retrieving logs...'), async () => {
const result = await (await registryTI.getClient(context)).runs.getLogSasUrl(registryTI.resourceGroup, registryTI.registryName, node.runId);
const storageBlob = await getStorageBlob();
const blobClient = new storageBlob.BlobClient(nonNullProp(result, 'logLink'));
const contentBuffer = await blobClient.downloadToBuffer();
const content = bufferToString(contentBuffer);
await openReadOnlyContent(node, content, '.log');
});
}

Просмотреть файл

@ -6,31 +6,32 @@
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { l10n, ProgressLocation, window } from "vscode";
import { ext } from "../../../extensionVariables";
import { registryExpectedContextValues } from "../../../tree/registries/registryContextValues";
import { RemoteTagTreeItem } from "../../../tree/registries/RemoteTagTreeItem";
import { registryRequest } from "../../../utils/registryRequestUtils";
import { AzureRegistryDataProvider, AzureTag } from "../../../tree/registries/Azure/AzureRegistryDataProvider";
import { getFullImageNameFromRegistryTagItem } from "../../../tree/registries/registryTreeUtils";
import { UnifiedRegistryItem } from "../../../tree/registries/UnifiedRegistryTreeDataProvider";
import { registryExperience } from "../../../utils/registryExperience";
export async function untagAzureImage(context: IActionContext, node?: RemoteTagTreeItem): Promise<void> {
export async function untagAzureImage(context: IActionContext, node?: UnifiedRegistryItem<AzureTag>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<RemoteTagTreeItem>(registryExpectedContextValues.azure.tag, {
...context,
suppressCreatePick: true,
noItemFoundErrorMessage: l10n.t('No images are available to untag')
// we can't pass in the azure tree provider because it's not a UnifiedRegistryItem and we need the provider to untag
node = await registryExperience<AzureTag>(context, {
registryFilter: { include: [ext.azureRegistryDataProvider.label] },
contextValueFilter: { include: /commontag/i },
});
}
const confirmUntag: string = l10n.t('Are you sure you want to untag image "{0}"? This does not delete the manifest referenced by the tag.', node.repoNameAndTag);
const fullTag = getFullImageNameFromRegistryTagItem(node.wrappedItem);
const confirmUntag: string = l10n.t('Are you sure you want to untag image "{0}"? This does not delete the manifest referenced by the tag.', fullTag);
// no need to check result - cancel will throw a UserCancelledError
await context.ui.showWarningMessage(confirmUntag, { modal: true }, { title: "Untag" });
const untagging = l10n.t('Untagging image "{0}"...', node.repoNameAndTag);
const repoTI = node.parent;
const untagging = l10n.t('Untagging image "{0}"...', fullTag);
await window.withProgress({ location: ProgressLocation.Notification, title: untagging }, async () => {
await registryRequest(repoTI, 'DELETE', `v2/_acr/${repoTI.repoName}/tags/${node.tag}`);
await repoTI.refresh(context);
const provider = node.provider as unknown as AzureRegistryDataProvider;
await provider.untagImage(node.wrappedItem);
});
// don't wait
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
window.showInformationMessage(l10n.t('Successfully untagged image "{0}".', node.repoNameAndTag));
void ext.registriesTree.refresh();
void window.showInformationMessage(l10n.t('Successfully untagged image "{0}".', fullTag));
}

Просмотреть файл

@ -5,15 +5,18 @@
import { IActionContext, openReadOnlyJson } from "@microsoft/vscode-azext-utils";
import { ext } from "../../../extensionVariables";
import { AzureRegistryTreeItem } from "../../../tree/registries/azure/AzureRegistryTreeItem";
import { AzureTaskRunTreeItem } from "../../../tree/registries/azure/AzureTaskRunTreeItem";
import { AzureTaskTreeItem } from "../../../tree/registries/azure/AzureTaskTreeItem";
import { registryExpectedContextValues } from "../../../tree/registries/registryContextValues";
import { AzureRegistry } from "../../../tree/registries/Azure/AzureRegistryDataProvider";
import { UnifiedRegistryItem } from "../../../tree/registries/UnifiedRegistryTreeDataProvider";
import { registryExperience } from "../../../utils/registryExperience";
export async function viewAzureProperties(context: IActionContext, node?: AzureRegistryTreeItem | AzureTaskTreeItem | AzureTaskRunTreeItem): Promise<void> {
export async function viewAzureProperties(context: IActionContext, node?: UnifiedRegistryItem<AzureRegistry>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<AzureRegistryTreeItem>(registryExpectedContextValues.azure.registry, context);
node = await registryExperience<AzureRegistry>(context, {
registryFilter: { include: [ext.azureRegistryDataProvider.label] },
contextValueFilter: { include: /commonregistry/i },
});
}
await openReadOnlyJson(node, node.properties);
const registryItem = node.wrappedItem;
await openReadOnlyJson({ label: registryItem.label, fullId: registryItem.id }, registryItem.registryProperties);
}

Просмотреть файл

@ -3,9 +3,8 @@
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { ext } from "../../extensionVariables";
export async function connectRegistry(context: IActionContext): Promise<void> {
await ext.registriesRoot.connectRegistry(context);
export async function connectRegistry(): Promise<void> {
await ext.registriesRoot.connectRegistryProvider();
}

Просмотреть файл

@ -4,20 +4,17 @@
*--------------------------------------------------------------------------------------------*/
import { IActionContext } from '@microsoft/vscode-azext-utils';
import { CommonTag } from '@microsoft/vscode-docker-registries';
import * as vscode from 'vscode';
import { ext } from '../../extensionVariables';
import { registryExpectedContextValues } from '../../tree/registries/registryContextValues';
import { RemoteTagTreeItem } from '../../tree/registries/RemoteTagTreeItem';
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
import { getFullImageNameFromRegistryTagItem } from '../../tree/registries/registryTreeUtils';
import { registryExperience } from '../../utils/registryExperience';
export async function copyRemoteFullTag(context: IActionContext, node?: RemoteTagTreeItem): Promise<string> {
export async function copyRemoteFullTag(context: IActionContext, node?: UnifiedRegistryItem<CommonTag>): Promise<string> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<RemoteTagTreeItem>([registryExpectedContextValues.dockerV2.tag, registryExpectedContextValues.dockerHub.tag], {
...context,
noItemFoundErrorMessage: vscode.l10n.t('No remote images are available to copy the full tag')
});
node = await registryExperience<CommonTag>(context, { contextValueFilter: { include: /commontag/i } });
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises
// Don't wait
void vscode.env.clipboard.writeText(node.fullTag);
return node.fullTag;
const fullTag = getFullImageNameFromRegistryTagItem(node.wrappedItem);
void vscode.env.clipboard.writeText(fullTag);
return fullTag;
}

Просмотреть файл

@ -3,34 +3,23 @@
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IActionContext, nonNullProp } from "@microsoft/vscode-azext-utils";
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { CommonTag, RegistryV2DataProvider } from "@microsoft/vscode-docker-registries";
import * as vscode from "vscode";
import { ext } from "../../extensionVariables";
import { AzureTaskRunTreeItem } from "../../tree/registries/azure/AzureTaskRunTreeItem";
import { DockerV2TagTreeItem } from "../../tree/registries/dockerV2/DockerV2TagTreeItem";
import { registryExpectedContextValues } from "../../tree/registries/registryContextValues";
import { UnifiedRegistryItem } from "../../tree/registries/UnifiedRegistryTreeDataProvider";
import { registryExperience } from "../../utils/registryExperience";
export async function copyRemoteImageDigest(context: IActionContext, node?: DockerV2TagTreeItem | AzureTaskRunTreeItem): Promise<void> {
export async function copyRemoteImageDigest(context: IActionContext, node?: UnifiedRegistryItem<CommonTag>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<DockerV2TagTreeItem>(registryExpectedContextValues.dockerV2.tag, {
...context,
noItemFoundErrorMessage: vscode.l10n.t('No remote images are available to copy the digest')
node = await registryExperience<CommonTag>(context, {
registryFilter: { exclude: [ext.dockerHubRegistryDataProvider.label] },
contextValueFilter: { include: /commontag/i, },
});
}
let digest: string;
if (node instanceof AzureTaskRunTreeItem) {
if (node.outputImage) {
digest = nonNullProp(node.outputImage, 'digest');
} else {
throw new Error(vscode.l10n.t('Failed to find output image for this task run.'));
}
} else {
await node.runWithTemporaryDescription(context, vscode.l10n.t('Getting digest...'), async () => {
digest = await (<DockerV2TagTreeItem>node).getDigest();
});
}
const v2DataProvider = node.provider as unknown as RegistryV2DataProvider;
const digest = await v2DataProvider.getImageDigest(node.wrappedItem);
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
vscode.env.clipboard.writeText(digest);
void vscode.env.clipboard.writeText(digest);
}

Просмотреть файл

@ -3,35 +3,51 @@
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DialogResponses, IActionContext } from '@microsoft/vscode-azext-utils';
import { l10n, ProgressLocation, window } from 'vscode';
import { DialogResponses, IActionContext, UserCancelledError, parseError } from '@microsoft/vscode-azext-utils';
import { CommonRegistryDataProvider, CommonTag } from '@microsoft/vscode-docker-registries';
import { ProgressLocation, l10n, window } from 'vscode';
import { ext } from '../../extensionVariables';
import { DockerV2TagTreeItem } from '../../tree/registries/dockerV2/DockerV2TagTreeItem';
import { registryExpectedContextValues } from '../../tree/registries/registryContextValues';
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
import { getImageNameFromRegistryTagItem } from '../../tree/registries/registryTreeUtils';
import { registryExperience } from '../../utils/registryExperience';
export async function deleteRemoteImage(context: IActionContext, node?: DockerV2TagTreeItem): Promise<void> {
export async function deleteRemoteImage(context: IActionContext, node?: UnifiedRegistryItem<CommonTag>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<DockerV2TagTreeItem>(registryExpectedContextValues.dockerV2.tag, {
...context,
suppressCreatePick: true,
noItemFoundErrorMessage: l10n.t('No remote images are available to delete')
node = await registryExperience<CommonTag>(context, {
registryFilter: { exclude: [ext.githubRegistryDataProvider.label, ext.dockerHubRegistryDataProvider.label] },
contextValueFilter: { include: /commontag/i },
});
}
const confirmDelete = l10n.t('Are you sure you want to delete image "{0}"? This will delete all images that have the same digest.', node.repoNameAndTag);
const provider = node.provider as unknown as CommonRegistryDataProvider;
if (typeof provider.deleteTag !== 'function') {
throw new Error(l10n.t('Deleting remote images is not supported on this registry.'));
}
const tagName = getImageNameFromRegistryTagItem(node.wrappedItem);
const confirmDelete = l10n.t('Are you sure you want to delete image "{0}"? This will delete all images that have the same digest.', tagName);
// no need to check result - cancel will throw a UserCancelledError
await context.ui.showWarningMessage(confirmDelete, { modal: true }, DialogResponses.deleteResponse);
const repoTI = node.parent;
const deleting = l10n.t('Deleting image "{0}"...', node.repoNameAndTag);
const deleting = l10n.t('Deleting image "{0}"...', tagName);
await window.withProgress({ location: ProgressLocation.Notification, title: deleting }, async () => {
await node.deleteTreeItem(context);
try {
await provider.deleteTag(node.wrappedItem);
} catch (error) {
const errorType: string = parseError(error).errorType.toLowerCase();
if (errorType === '405' || errorType === 'unsupported') {
// Don't wait
// eslint-disable-next-line @typescript-eslint/no-floating-promises
context.ui.showWarningMessage('Deleting remote images is not supported on this registry. It may need to be enabled.', { learnMoreLink: 'https://aka.ms/AA7jsql' });
throw new UserCancelledError();
} else {
throw error;
}
}
});
// Other tags that also matched the image may have been deleted, so refresh the whole repository
await repoTI.refresh(context);
const message = l10n.t('Successfully deleted image "{0}".', node.repoNameAndTag);
// don't wait
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
window.showInformationMessage(message);
void ext.registriesTree.refresh();
void window.showInformationMessage(l10n.t('Successfully deleted image "{0}".', tagName));
}

Просмотреть файл

@ -3,17 +3,16 @@
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IActionContext, InvalidTreeItem } from "@microsoft/vscode-azext-utils";
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { CommonRegistry } from "@microsoft/vscode-docker-registries";
import { ext } from "../../extensionVariables";
import { ICachedRegistryProvider } from "../../tree/registries/ICachedRegistryProvider";
import { IRegistryProviderTreeItem } from "../../tree/registries/IRegistryProviderTreeItem";
import { UnifiedRegistryItem } from "../../tree/registries/UnifiedRegistryTreeDataProvider";
import { registryExperience } from "../../utils/registryExperience";
export async function disconnectRegistry(context: IActionContext, node?: InvalidTreeItem | IRegistryProviderTreeItem): Promise<void> {
let cachedProvider: ICachedRegistryProvider | undefined;
if (node instanceof InvalidTreeItem) {
cachedProvider = <ICachedRegistryProvider>node.data;
} else if (node) {
cachedProvider = node.cachedProvider;
export async function disconnectRegistry(context: IActionContext, node?: UnifiedRegistryItem<unknown>): Promise<void> {
if (!node) {
node = await registryExperience<CommonRegistry>(context, { registryFilter: { exclude: [ext.genericRegistryV2DataProvider.label] } });
}
await ext.registriesRoot.disconnectRegistry(context, cachedProvider);
await ext.registriesTree.disconnectRegistryProvider(node);
}

Просмотреть файл

@ -4,30 +4,32 @@
*--------------------------------------------------------------------------------------------*/
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { CommonRegistryItem, isRegistry, isRepository, isTag } from "@microsoft/vscode-docker-registries";
import * as vscode from "vscode";
import { dockerHubUrl } from "../../../constants";
import { ext } from "../../../extensionVariables";
import { DockerHubNamespaceTreeItem } from "../../../tree/registries/dockerHub/DockerHubNamespaceTreeItem";
import { DockerHubRepositoryTreeItem } from "../../../tree/registries/dockerHub/DockerHubRepositoryTreeItem";
import { registryExpectedContextValues } from "../../../tree/registries/registryContextValues";
import { RemoteTagTreeItem } from "../../../tree/registries/RemoteTagTreeItem";
import { UnifiedRegistryItem } from "../../../tree/registries/UnifiedRegistryTreeDataProvider";
import { registryExperience } from "../../../utils/registryExperience";
export async function openDockerHubInBrowser(context: IActionContext, node?: DockerHubNamespaceTreeItem | DockerHubRepositoryTreeItem | RemoteTagTreeItem): Promise<void> {
export async function openDockerHubInBrowser(context: IActionContext, node?: UnifiedRegistryItem<CommonRegistryItem>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<DockerHubNamespaceTreeItem>(registryExpectedContextValues.dockerHub.registry, {
...context,
noItemFoundErrorMessage: vscode.l10n.t('No Docker Hub registries available to browse')
node = await registryExperience<CommonRegistryItem>(context, {
registryFilter: { include: [ext.dockerHubRegistryDataProvider.label] },
contextValueFilter: { include: [/commonregistry/i] },
});
}
let url = dockerHubUrl;
if (node instanceof DockerHubNamespaceTreeItem) {
url += `u/${node.namespace}`;
} else if (node instanceof DockerHubRepositoryTreeItem) {
url += `r/${node.parent.namespace}/${node.repoName}`;
const dockerHubItem = node.wrappedItem;
if (isRegistry(dockerHubItem)) {
url = `${url}u/${dockerHubItem.label}`;
} else if (isRepository(dockerHubItem)) {
url = `${url}r/${dockerHubItem.parent.label}/${dockerHubItem.label}`;
} else if (isTag(dockerHubItem)) {
url = `${url}r/${dockerHubItem.parent.parent.label}/${dockerHubItem.parent.label}/tags`;
} else {
const repoTI = <DockerHubRepositoryTreeItem>node.parent;
url += `r/${repoTI.parent.namespace}/${repoTI.repoName}/tags`;
throw new Error(`Unexpected node type ${dockerHubItem.additionalContextValues || ''}`);
}
await vscode.env.openExternal(vscode.Uri.parse(url));

Просмотреть файл

@ -0,0 +1,21 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { ext } from "../../../extensionVariables";
import { UnifiedRegistryItem } from "../../../tree/registries/UnifiedRegistryTreeDataProvider";
export async function addTrackedGenericV2Registry(context: IActionContext, node?: UnifiedRegistryItem<unknown>): Promise<void> {
// if there are already registries, add a new registry to the existing root node
if (ext.genericRegistryV2DataProvider.hasTrackedRegistries()) {
await ext.genericRegistryV2DataProvider.addTrackedRegistry();
} else {
// if there are no registries, connect as usual
await ext.registriesTree.connectRegistryProvider(ext.genericRegistryV2DataProvider);
}
// don't wait
void ext.registriesTree.refresh();
}

Просмотреть файл

@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { V2Registry } from "@microsoft/vscode-docker-registries";
import { ext } from "../../../extensionVariables";
import { UnifiedRegistryItem } from "../../../tree/registries/UnifiedRegistryTreeDataProvider";
import { registryExperience } from "../../../utils/registryExperience";
export async function removeTrackedGenericV2Registry(context: IActionContext, node?: UnifiedRegistryItem<V2Registry>): Promise<void> {
if (!node) {
node = await registryExperience<V2Registry>(context, {
registryFilter: { include: [ext.genericRegistryV2DataProvider.label] },
contextValueFilter: { include: /commonregistry/i },
});
}
await ext.genericRegistryV2DataProvider.removeTrackedRegistry(node.wrappedItem);
// remove the provider if it's the last one
if (!ext.genericRegistryV2DataProvider.hasTrackedRegistries()) {
await ext.registriesTree.disconnectRegistryProvider(node.parent);
}
// don't wait
void ext.registriesTree.refresh();
}

Просмотреть файл

@ -4,32 +4,25 @@
*--------------------------------------------------------------------------------------------*/
import { IActionContext, parseError } from '@microsoft/vscode-azext-utils';
import { CommonRegistry } from '@microsoft/vscode-docker-registries';
import * as stream from 'stream';
import * as vscode from 'vscode';
import { NULL_GUID } from '../../constants';
import { ext } from '../../extensionVariables';
import { registryExpectedContextValues } from '../../tree/registries/registryContextValues';
import { RegistryTreeItemBase } from '../../tree/registries/RegistryTreeItemBase';
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
import { registryExperience } from '../../utils/registryExperience';
export async function logInToDockerCli(context: IActionContext, node?: RegistryTreeItemBase): Promise<void> {
export async function logInToDockerCli(context: IActionContext, node?: UnifiedRegistryItem<CommonRegistry>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<RegistryTreeItemBase>(registryExpectedContextValues.all.registry, context);
node = await registryExperience<CommonRegistry>(context, { contextValueFilter: { include: /commonregistry/i } });
}
const creds = await node.getDockerCliCredentials();
const auth: { username?: string, password?: string, token?: string } = creds.auth || {};
let username: string | undefined;
let password: string | undefined;
if (auth.token) {
username = NULL_GUID;
password = auth.token;
} else if (auth.password) {
username = auth.username;
password = auth.password;
}
const creds = await node.provider?.getLoginInformation?.(node.wrappedItem);
const username = creds?.username;
const secret = creds?.secret;
const server = creds?.server;
if (!username || !password) {
ext.outputChannel.warn(vscode.l10n.t('Skipping login for "{0}" because it does not require authentication.', creds.registryPath));
if (!username || !secret) {
ext.outputChannel.warn(vscode.l10n.t('Skipping login for "{0}" because it does not require authentication.', node.provider.label));
} else {
const progressOptions: vscode.ProgressOptions = {
location: vscode.ProgressLocation.Notification,
@ -42,10 +35,10 @@ export async function logInToDockerCli(context: IActionContext, node?: RegistryT
client => client.login({
username: username,
passwordStdIn: true,
registry: creds.registryPath,
registry: server
}),
{
stdInPipe: stream.Readable.from(password),
stdInPipe: stream.Readable.from(secret),
}
);
ext.outputChannel.info('Login succeeded.');

Просмотреть файл

@ -4,17 +4,21 @@
*--------------------------------------------------------------------------------------------*/
import { IActionContext } from '@microsoft/vscode-azext-utils';
import { CommonRegistry } from '@microsoft/vscode-docker-registries';
import { l10n } from 'vscode';
import { ext } from '../../extensionVariables';
import { TaskCommandRunnerFactory } from '../../runtimes/runners/TaskCommandRunnerFactory';
import { registryExpectedContextValues } from '../../tree/registries/registryContextValues';
import { RegistryTreeItemBase } from '../../tree/registries/RegistryTreeItemBase';
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
import { registryExperience } from '../../utils/registryExperience';
export async function logOutOfDockerCli(context: IActionContext, node?: RegistryTreeItemBase): Promise<void> {
export async function logOutOfDockerCli(context: IActionContext, node?: UnifiedRegistryItem<CommonRegistry>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<RegistryTreeItemBase>(registryExpectedContextValues.all.registry, context);
node = await registryExperience<CommonRegistry>(context, { contextValueFilter: { include: /commonregistry/i } });
}
const serverUrl = (await node.provider.getLoginInformation?.(node.wrappedItem))?.server;
if (!serverUrl) {
throw new Error(l10n.t('Unable to get server URL'));
}
const creds = await node.getDockerCliCredentials();
const client = await ext.runtimeManager.getClient();
const taskCRF = new TaskCommandRunnerFactory(
@ -24,6 +28,6 @@ export async function logOutOfDockerCli(context: IActionContext, node?: Registry
);
await taskCRF.getCommandRunner()(
client.logout({ registry: creds.registryPath })
client.logout({ registry: serverUrl }),
);
}

Просмотреть файл

@ -4,32 +4,33 @@
*--------------------------------------------------------------------------------------------*/
import { IActionContext } from '@microsoft/vscode-azext-utils';
import { CommonRegistry, CommonRepository, CommonTag } from '@microsoft/vscode-docker-registries/lib/clients/Common/models';
import { ext } from '../../extensionVariables';
import { TaskCommandRunnerFactory } from '../../runtimes/runners/TaskCommandRunnerFactory';
import { registryExpectedContextValues } from '../../tree/registries/registryContextValues';
import { RegistryTreeItemBase } from '../../tree/registries/RegistryTreeItemBase';
import { RemoteRepositoryTreeItemBase } from '../../tree/registries/RemoteRepositoryTreeItemBase';
import { RemoteTagTreeItem } from '../../tree/registries/RemoteTagTreeItem';
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
import { getFullImageNameFromRegistryTagItem, getFullRepositoryNameFromRepositoryItem } from '../../tree/registries/registryTreeUtils';
import { registryExperience } from '../../utils/registryExperience';
import { logInToDockerCli } from './logInToDockerCli';
export async function pullRepository(context: IActionContext, node?: RemoteRepositoryTreeItemBase): Promise<void> {
export async function pullRepository(context: IActionContext, node?: UnifiedRegistryItem<CommonRepository>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<RemoteRepositoryTreeItemBase>(registryExpectedContextValues.all.repository, context);
node = await registryExperience<CommonRepository>(context, { contextValueFilter: { include: /commonrepository/i } });
}
await pullImages(context, node.parent, node.repoName, true);
await pullImages(context, node.parent, getFullRepositoryNameFromRepositoryItem(node.wrappedItem), true);
}
export async function pullImageFromRepository(context: IActionContext, node?: RemoteTagTreeItem): Promise<void> {
export async function pullImageFromRepository(context: IActionContext, node?: UnifiedRegistryItem<CommonTag>): Promise<void> {
if (!node) {
node = await ext.registriesTree.showTreeItemPicker<RemoteTagTreeItem>(registryExpectedContextValues.all.tag, context);
node = await registryExperience<CommonTag>(context, { contextValueFilter: { include: /commontag/i } });
}
await pullImages(context, node.parent.parent, node.repoNameAndTag, false);
await pullImages(context, node.parent.parent, getFullImageNameFromRegistryTagItem(node.wrappedItem), false);
}
async function pullImages(context: IActionContext, node: RegistryTreeItemBase, imageRequest: string, allTags: boolean): Promise<void> {
await logInToDockerCli(context, node);
async function pullImages(context: IActionContext, node: UnifiedRegistryItem<unknown>, imageRequest: string, allTags: boolean): Promise<void> {
const registryNode = node as UnifiedRegistryItem<CommonRegistry>;
await logInToDockerCli(context, registryNode);
const client = await ext.runtimeManager.getClient();
const taskCRF = new TaskCommandRunnerFactory({
@ -39,7 +40,7 @@ async function pullImages(context: IActionContext, node: RegistryTreeItemBase, i
await taskCRF.getCommandRunner()(
client.pullImage(
{
imageRef: `${node.baseImagePath}/${imageRequest}`,
imageRef: imageRequest,
allTags: allTags,
}
)

Просмотреть файл

@ -4,16 +4,22 @@
*--------------------------------------------------------------------------------------------*/
import { IActionContext } from "@microsoft/vscode-azext-utils";
import { RegistryConnectError, V2Registry, isGenericV2Registry } from "@microsoft/vscode-docker-registries";
import { l10n } from 'vscode';
import { ext } from "../../extensionVariables";
import { RegistryConnectErrorTreeItem } from "../../tree/registries/RegistryConnectErrorTreeItem";
import { UnifiedRegistryItem } from "../../tree/registries/UnifiedRegistryTreeDataProvider";
export async function reconnectRegistry(context: IActionContext, node?: RegistryConnectErrorTreeItem): Promise<void> {
if (!node?.cachedProvider || !node?.provider) {
export async function reconnectRegistry(context: IActionContext, node?: UnifiedRegistryItem<RegistryConnectError>): Promise<void> {
if (!node?.provider || !node?.wrappedItem || !node?.parent) {
// This is not expected ever, so we'll throw an error which can be bubbled up to a Report Issue if it does
throw new Error(l10n.t('Unable to determine provider to re-enter credentials. Please disconnect and connect again.'));
}
await ext.registriesRoot.disconnectRegistry(context, node.cachedProvider);
await ext.registriesRoot.connectRegistry(context, node.provider, node.url);
if (isGenericV2Registry(node.parent.wrappedItem)) {
await ext.genericRegistryV2DataProvider.removeTrackedRegistry(node.parent.wrappedItem as V2Registry);
await ext.genericRegistryV2DataProvider.addTrackedRegistry();
} else {
await ext.registriesTree.disconnectRegistryProvider(node.parent);
await ext.registriesRoot.connectRegistryProvider(node.provider);
}
}

Просмотреть файл

@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import { IActionContext, IAzureQuickPickItem, IAzureQuickPickOptions, UserCancelledError } from '@microsoft/vscode-azext-utils';
import { PortBinding, VoidCommandResponse } from '@microsoft/vscode-container-client';
import * as vscode from 'vscode';
import { ext } from '../extensionVariables';
import { PortBinding, VoidCommandResponse } from '../runtimes/docker';
import { isDockerComposeClient } from '../runtimes/OrchestratorRuntimeManager';
import { resolveVariables } from '../utils/resolveVariables';

Просмотреть файл

@ -4,11 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import { DialogResponses, IActionContext, UserCancelledError } from '@microsoft/vscode-azext-utils';
import { CommandLineArgs, ContainerOS, VoidCommandResponse, composeArgs, withArg, withQuotedArg } from '@microsoft/vscode-container-client';
import * as fse from 'fs-extra';
import * as path from 'path';
import { DebugConfiguration, MessageItem, ProgressLocation, l10n, window } from 'vscode';
import { ext } from '../../extensionVariables';
import { CommandLineArgs, ContainerOS, VoidCommandResponse, composeArgs, withArg, withQuotedArg } from '../../runtimes/docker';
import { NetCoreTaskHelper, NetCoreTaskOptions } from '../../tasks/netcore/NetCoreTaskHelper';
import { ContainerTreeItem } from '../../tree/containers/ContainerTreeItem';
import { getNetCoreProjectInfo } from '../../utils/netCoreUtils';

Просмотреть файл

@ -25,7 +25,6 @@ import { registerListeners } from './telemetry/registerListeners';
import { registerTrees } from './tree/registerTrees';
import { AlternateYamlLanguageServiceClientFeature } from './utils/AlternateYamlLanguageServiceClientFeature';
import { AzExtLogOutputChannelWrapper } from './utils/AzExtLogOutputChannelWrapper';
import { AzureAccountExtensionListener } from './utils/AzureAccountExtensionListener';
import { logDockerEnvironment, logSystemInfo } from './utils/diagnostics';
import { DocumentSettingsClientFeature } from './utils/DocumentSettingsClientFeature';
import { migrateOldEnvironmentSettingsIfNeeded } from './utils/migrateOldEnvironmentSettingsIfNeeded';
@ -133,13 +132,16 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<unknown |
// Don't wait
void migrateOldEnvironmentSettingsIfNeeded();
// Call command to activate registry provider extensions
// Don't wait
void vscode.commands.executeCommand('vscode-docker.activateRegistryProviders');
return new DockerExtensionApi(ctx);
}
export async function deactivate(ctx: vscode.ExtensionContext): Promise<void> {
await callWithTelemetryAndErrorHandling('docker.deactivate', async (activateContext: IActionContext) => {
activateContext.telemetry.properties.isActivationEvent = 'true';
AzureAccountExtensionListener.dispose();
await Promise.all([
dockerfileLanguageClient.stop(),

Просмотреть файл

@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { AzExtTreeDataProvider, AzExtTreeItem, IExperimentationServiceAdapter } from '@microsoft/vscode-azext-utils';
import { DockerHubRegistryDataProvider, GenericRegistryV2DataProvider, GitHubRegistryDataProvider } from '@microsoft/vscode-docker-registries';
import { ExtensionContext, StatusBarItem, TreeView } from 'vscode';
import { ContainerRuntimeManager } from './runtimes/ContainerRuntimeManager';
import { OrchestratorRuntimeManager } from './runtimes/OrchestratorRuntimeManager';
@ -13,7 +14,8 @@ import { ContainersTreeItem } from './tree/containers/ContainersTreeItem';
import { ContextsTreeItem } from './tree/contexts/ContextsTreeItem';
import { ImagesTreeItem } from './tree/images/ImagesTreeItem';
import { NetworksTreeItem } from './tree/networks/NetworksTreeItem';
import { RegistriesTreeItem } from './tree/registries/RegistriesTreeItem';
import { AzureRegistryDataProvider } from './tree/registries/Azure/AzureRegistryDataProvider';
import { UnifiedRegistryItem, UnifiedRegistryTreeDataProvider } from './tree/registries/UnifiedRegistryTreeDataProvider';
import { VolumesTreeItem } from './tree/volumes/VolumesTreeItem';
import { AzExtLogOutputChannelWrapper } from './utils/AzExtLogOutputChannelWrapper';
@ -45,9 +47,13 @@ export namespace ext {
export const prefix: string = 'docker';
export let registriesTree: AzExtTreeDataProvider;
export let registriesTreeView: TreeView<AzExtTreeItem>;
export let registriesRoot: RegistriesTreeItem;
export let registriesTree: UnifiedRegistryTreeDataProvider;
export let registriesTreeView: TreeView<UnifiedRegistryItem<unknown>>;
export let registriesRoot: UnifiedRegistryTreeDataProvider;
export let genericRegistryV2DataProvider: GenericRegistryV2DataProvider;
export let azureRegistryDataProvider: AzureRegistryDataProvider;
export let dockerHubRegistryDataProvider: DockerHubRegistryDataProvider;
export let githubRegistryDataProvider: GitHubRegistryDataProvider;
export let volumesTree: AzExtTreeDataProvider;
export let volumesTreeView: TreeView<AzExtTreeItem>;

Просмотреть файл

@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DockerClient, IContainersClient } from './docker';
import { DockerClient, IContainersClient } from '@microsoft/vscode-container-client';
import { ContextManager, IContextManager } from './ContextManager';
import { RuntimeManager } from './RuntimeManager';

Просмотреть файл

@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { InspectContextsItem, ListContextItem } from './docker';
import { InspectContextsItem, ListContextItem } from '@microsoft/vscode-container-client';
import * as vscode from 'vscode';
import { ext } from '../extensionVariables';

Просмотреть файл

@ -3,9 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { isAutoConfigurableDockerComposeClient } from './clients/AutoConfigurableDockerComposeClient';
import { DockerComposeClient, IContainerOrchestratorClient } from './docker';
import { DockerComposeClient, IContainerOrchestratorClient } from '@microsoft/vscode-container-client';
import { RuntimeManager } from './RuntimeManager';
import { isAutoConfigurableDockerComposeClient } from './clients/AutoConfigurableDockerComposeClient';
export class OrchestratorRuntimeManager extends RuntimeManager<IContainerOrchestratorClient> {
public readonly onOrchestratorRuntimeClientRegistered = this.runtimeClientRegisteredEmitter.event;

Просмотреть файл

@ -3,8 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ClientIdentity } from '@microsoft/vscode-container-client';
import * as vscode from 'vscode';
import { ClientIdentity } from './docker';
export abstract class RuntimeManager<TClient extends ClientIdentity> extends vscode.Disposable {
private readonly _runtimeClients = new Map<string, TClient>();

Просмотреть файл

@ -3,9 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DockerClient } from '@microsoft/vscode-container-client';
import * as vscode from 'vscode';
import { ext } from '../../extensionVariables';
import { DockerClient } from '../docker';
import { AutoConfigurableClient } from './AutoConfigurableClient';
export class AutoConfigurableDockerClient extends DockerClient implements AutoConfigurableClient {

Просмотреть файл

@ -3,11 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DockerComposeClient, IContainerOrchestratorClient } from '@microsoft/vscode-container-client';
import * as vscode from 'vscode';
import { ext } from '../../extensionVariables';
import { execAsync } from '../../utils/execAsync';
import { AsyncLazy } from '../../utils/lazy';
import { DockerComposeClient, IContainerOrchestratorClient } from '../docker';
import { isDockerComposeClient } from '../OrchestratorRuntimeManager';
import { AutoConfigurableClient } from './AutoConfigurableClient';

Просмотреть файл

@ -1,46 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ClientIdentity } from '../contracts/ContainerClient';
export abstract class ConfigurableClient implements ClientIdentity {
public constructor(
public readonly id: string,
commandName: string,
displayName: string,
description: string
) {
this.#commandName = commandName;
this.#displayName = displayName;
this.#description = description;
}
#commandName: string;
public get commandName(): string {
return this.#commandName;
}
public set commandName(value: string) {
this.#commandName = value;
}
#displayName: string;
public get displayName(): string {
return this.#displayName;
}
public set displayName(value: string) {
this.#displayName = value;
}
#description: string;
public get description(): string {
return this.#description;
}
public set description(value: string) {
this.#description = value;
}
}

Просмотреть файл

@ -1,217 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { PromiseCommandResponse, VoidCommandResponse } from "../../contracts/CommandRunner";
import { IContainersClient, InspectContextsCommandOptions, InspectContextsItem, ListContextItem, ListContextsCommandOptions, RemoveContextsCommandOptions, UseContextCommandOptions } from "../../contracts/ContainerClient";
import { asIds } from "../../utils/asIds";
import { CommandLineArgs, composeArgs, withArg } from "../../utils/commandLineBuilder";
import { DockerClientBase } from "../DockerClientBase/DockerClientBase";
import { withDockerJsonFormatArg } from "../DockerClientBase/withDockerJsonFormatArg";
import { isDockerContextRecord } from "./DockerContextRecord";
import { isDockerInspectContextRecord } from "./DockerInspectContextRecord";
export class DockerClient extends DockerClientBase implements IContainersClient {
/**
* The ID of the Docker client
*/
public static ClientId = 'com.microsoft.visualstudio.containers.docker';
/**
* Constructs a new {@link DockerClient}
* @param commandName (Optional, default `docker`) The command that will be run
* as the base command. If quoting is necessary, it is the responsibility of the
* caller to add.
* @param displayName (Optional, default 'Docker') The human-friendly display
* name of the client
* @param description (Optional, with default) The human-friendly description of
* the client
*/
public constructor(
commandName: string = 'docker',
displayName: string = 'Docker',
description: string = 'Runs container commands using the Docker CLI'
) {
super(
DockerClient.ClientId,
commandName,
displayName,
description
);
}
//#region Context Commands
//#region ListContexts Command
private getListContextsCommandArgs(options: ListContextsCommandOptions): CommandLineArgs {
return composeArgs(
withArg('context', 'ls'),
withDockerJsonFormatArg,
)();
}
private async parseListContextsCommandOutput(
output: string,
strict: boolean,
): Promise<ListContextItem[]> {
const contexts = new Array<ListContextItem>();
try {
// Docker returns JSON per-line output, so we need to split each line
// and parse as independent JSON objects
output.split('\n').forEach((contextJson) => {
try {
// Ignore empty lines when parsing
if (!contextJson) {
return;
}
const rawContext = JSON.parse(contextJson);
// Validate that the image object matches the expected output
// for the list contexts command
if (!isDockerContextRecord(rawContext)) {
throw new Error('Invalid context JSON');
}
contexts.push({
name: rawContext.Name,
current: rawContext.Current,
description: rawContext.Description,
containerEndpoint: rawContext.DockerEndpoint,
});
} catch (err) {
if (strict) {
throw err;
}
}
});
} catch (err) {
if (strict) {
throw err;
}
}
return contexts;
}
override async listContexts(options: ListContextsCommandOptions): Promise<PromiseCommandResponse<ListContextItem[]>> {
return {
command: this.commandName,
args: this.getListContextsCommandArgs(options),
parse: this.parseListContextsCommandOutput,
};
}
//#endregion
//#region RemoveContexts Command
private getRemoveContextsCommandArgs(options: RemoveContextsCommandOptions): CommandLineArgs {
return composeArgs(
withArg('context', 'rm'),
withArg(...options.contexts),
withArg('--force'),
)();
}
private async parseRemoveContextsCommandOutput(
output: string,
strict: boolean,
): Promise<string[]> {
return asIds(output);
}
override async removeContexts(options: RemoveContextsCommandOptions): Promise<PromiseCommandResponse<string[]>> {
return {
command: this.commandName,
args: this.getRemoveContextsCommandArgs(options),
parse: this.parseRemoveContextsCommandOutput,
};
}
//#endregion
//#region UseContext Command
private getUseContextCommandArgs(options: UseContextCommandOptions): CommandLineArgs {
return composeArgs(
withArg('context', 'use'),
withArg(options.context),
)();
}
override async useContext(options: UseContextCommandOptions): Promise<VoidCommandResponse> {
return {
command: this.commandName,
args: this.getUseContextCommandArgs(options),
};
}
//#endregion
//#region InspectContexts Command
private getInspectContextsCommandArgs(options: InspectContextsCommandOptions): CommandLineArgs {
return composeArgs(
withArg('context', 'inspect'),
withDockerJsonFormatArg,
withArg(...options.contexts),
)();
}
private async parseInspectContextsCommandOutput(
output: string,
strict: boolean,
): Promise<InspectContextsItem[]> {
try {
return output.split('\n').reduce<Array<InspectContextsItem>>((volumes, inspectString) => {
if (!inspectString) {
return volumes;
}
try {
const inspect = JSON.parse(inspectString);
if (!isDockerInspectContextRecord(inspect)) {
throw new Error('Invalid context inspect json');
}
// Return the normalized InspectVolumesItem record
const volume: InspectContextsItem = {
name: inspect.Name,
description: inspect.Metadata?.Description,
raw: inspectString,
};
return [...volumes, volume];
} catch (err) {
if (strict) {
throw err;
}
}
return volumes;
}, new Array<InspectContextsItem>());
} catch (err) {
if (strict) {
throw err;
}
}
return new Array<InspectContextsItem>();
}
override async inspectContexts(options: InspectContextsCommandOptions): Promise<PromiseCommandResponse<InspectContextsItem[]>> {
return {
command: this.commandName,
args: this.getInspectContextsCommandArgs(options),
parse: this.parseInspectContextsCommandOutput,
};
}
//#endregion
//#endregion
}

Просмотреть файл

@ -1,29 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export type DockerContextRecord = {
Name: string;
Current: boolean;
Description?: string;
DockerEndpoint?: string;
};
export function isDockerContextRecord(maybeContext: unknown): maybeContext is DockerContextRecord {
const context = maybeContext as DockerContextRecord;
if (!context || typeof context !== 'object') {
return false;
}
if (typeof context.Name !== 'string') {
return false;
}
if (typeof context.Current !== 'boolean') {
return false;
}
return true;
}

Просмотреть файл

@ -1,16 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export type DockerInspectContextRecord = {
Name: string;
Metadata?: {
Description?: string;
}
};
// TODO: Actually test properties
export function isDockerInspectContextRecord(maybeContext: unknown): maybeContext is DockerInspectContextRecord {
return true;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,50 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { EventAction, EventType } from "../../contracts/ContainerClient";
export type DockerEventRecord = {
Type: EventType;
Action: EventAction;
Actor: {
ID: string;
Attributes: Record<string, unknown>;
};
time: number;
};
export function isDockerEventRecord(maybeEvent: unknown): maybeEvent is DockerEventRecord {
const event = maybeEvent as DockerEventRecord;
if (!event || typeof event !== 'object') {
return false;
}
if (typeof event.Type !== 'string') {
return false;
}
if (typeof event.Action !== 'string') {
return false;
}
if (typeof event.Actor !== 'object') {
return false;
}
if (typeof event.Actor.ID !== 'string') {
return false;
}
if (typeof event.Actor.Attributes !== 'object') {
return false;
}
if (typeof event.time !== 'number') {
return false;
}
return true;
}

Просмотреть файл

@ -1,21 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ContainerOS, isContainerOS } from "../../contracts/ContainerClient";
export type DockerInfoRecord = {
OperatingSystem?: string;
OSType?: ContainerOS;
};
export function isDockerInfoRecord(maybeInfo: unknown): maybeInfo is DockerInfoRecord {
const info = maybeInfo as DockerInfoRecord;
if (typeof info.OSType === 'string' && !isContainerOS(info.OSType)) {
return false;
}
return true;
}

Просмотреть файл

@ -1,177 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { InspectContainersItem, InspectContainersItemMount, InspectContainersItemNetwork, PortBinding } from '../../contracts/ContainerClient';
import { dayjs } from '../../utils/dayjs';
import { toArray } from '../../utils/toArray';
import { parseDockerLikeEnvironmentVariables } from './parseDockerLikeEnvironmentVariables';
import { parseDockerLikeImageName } from './parseDockerLikeImageName';
export type DockerInspectContainerPortHost = {
HostIp?: string;
HostPort?: number;
};
export type DockerInspectContainerBindMount = {
Type: 'bind';
Source: string;
Destination: string;
RW: boolean;
};
export type DockerInspectContainerVolumeMount = {
Type: 'volume';
Name: string;
Source: string;
Destination: string;
Driver: string;
RW: boolean;
};
export type DockerInspectContainerMount =
| DockerInspectContainerBindMount
| DockerInspectContainerVolumeMount;
export type DockerInspectNetwork = {
Gateway: string;
IPAddress: string;
MacAddress: string;
};
export type DockerInspectContainerConfig = {
Image: string;
Status: string;
Entrypoint: Array<string> | string | null;
Cmd: Array<string> | string | null;
Env?: Array<string> | null;
Labels?: Record<string, string> | null;
WorkingDir?: string | null;
};
export type DockerInspectContainerHostConfig = {
PublishAllPorts?: boolean | null;
Isolation?: string | null;
};
export type DockerInspectContainerNetworkSettings = {
Networks?: Record<string, DockerInspectNetwork> | null;
IPAddress?: string;
Ports?: Record<string, Array<DockerInspectContainerPortHost>> | null;
};
export type DockerInspectContainerState = {
Status?: string;
StartedAt?: string;
FinishedAt?: string;
};
export type DockerInspectContainerRecord = {
Id: string;
Name: string;
Image: string;
Platform: string;
Created: string;
Mounts: Array<DockerInspectContainerMount>;
State: DockerInspectContainerState;
Config: DockerInspectContainerConfig;
HostConfig: DockerInspectContainerHostConfig;
NetworkSettings: DockerInspectContainerNetworkSettings;
};
// TODO: Actually test properties
export function isDockerInspectContainerRecord(maybeContainer: unknown): maybeContainer is DockerInspectContainerRecord {
return true;
}
export function normalizeDockerInspectContainerRecord(container: DockerInspectContainerRecord): InspectContainersItem {
// Parse the environment variables assigned to the container at runtime
const environmentVariables = parseDockerLikeEnvironmentVariables(container.Config?.Env || []);
// Parse the networks assigned to the container and normalize to InspectContainersItemNetwork
// records
const networks = Object.entries(container.NetworkSettings?.Networks || {}).map<InspectContainersItemNetwork>(([name, dockerNetwork]) => {
return {
name,
gateway: dockerNetwork.Gateway || undefined,
ipAddress: dockerNetwork.IPAddress || undefined,
macAddress: dockerNetwork.MacAddress || undefined,
};
});
// Parse the exposed ports for the container and normalize to a PortBinding record
const ports = Object.entries(container.NetworkSettings?.Ports || {}).map<PortBinding>(([rawPort, hostBinding]) => {
const [port, protocol] = rawPort.split('/');
return {
hostIp: hostBinding?.[0]?.HostIp,
hostPort: hostBinding?.[0]?.HostPort,
containerPort: parseInt(port),
protocol: protocol.toLowerCase() === 'tcp'
? 'tcp'
: protocol.toLowerCase() === 'udp'
? 'udp'
: undefined,
};
});
// Parse the volume and bind mounts associated with the given runtime and normalize to
// InspectContainersItemMount records
const mounts = (container.Mounts || []).reduce<Array<InspectContainersItemMount>>((curMounts, mount) => {
switch (mount?.Type) {
case 'bind':
return [...curMounts, {
type: 'bind',
source: mount.Source,
destination: mount.Destination,
readOnly: !mount.RW,
}];
case 'volume':
return [...curMounts, {
type: 'volume',
name: mount.Name,
source: mount.Source,
destination: mount.Destination,
driver: mount.Driver,
readOnly: !mount.RW,
}];
}
}, new Array<InspectContainersItemMount>());
const labels = container.Config?.Labels ?? {};
const createdAt = dayjs.utc(container.Created);
const startedAt = container.State?.StartedAt
? dayjs.utc(container.State?.StartedAt)
: undefined;
const finishedAt = container.State?.FinishedAt
? dayjs.utc(container.State?.FinishedAt)
: undefined;
// Return the normalized InspectContainersItem record
return {
id: container.Id,
name: container.Name,
imageId: container.Image,
image: parseDockerLikeImageName(container.Config.Image),
isolation: container.HostConfig?.Isolation,
status: container.State?.Status,
environmentVariables,
networks,
ipAddress: container.NetworkSettings?.IPAddress ? container.NetworkSettings?.IPAddress : undefined,
ports,
mounts,
labels,
entrypoint: toArray(container.Config?.Entrypoint ?? []),
command: toArray(container.Config?.Cmd ?? []),
currentDirectory: container.Config?.WorkingDir || undefined,
createdAt: createdAt.toDate(),
startedAt: startedAt && (startedAt.isSame(createdAt) || startedAt.isAfter(createdAt))
? startedAt.toDate()
: undefined,
finishedAt: finishedAt && (finishedAt.isSame(createdAt) || finishedAt.isAfter(createdAt))
? finishedAt.toDate()
: undefined,
raw: JSON.stringify(container),
};
}

Просмотреть файл

@ -1,171 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ImageNameInfo, InspectImagesItem, PortBinding } from "../../contracts/ContainerClient";
import { dayjs } from '../../utils/dayjs';
import { toArray } from "../../utils/toArray";
import { parseDockerLikeEnvironmentVariables } from "./parseDockerLikeEnvironmentVariables";
import { parseDockerLikeImageName } from "./parseDockerLikeImageName";
export type DockerInspectImageConfig = {
Entrypoint?: Array<string> | string | null;
Cmd?: Array<string> | string | null;
Env?: Array<string>,
Labels?: Record<string, string> | null,
ExposedPorts?: Record<string, unknown> | null;
Volumes?: Record<string, unknown> | null;
WorkingDir?: string | null;
User?: string | null;
};
export type DockerInspectImageRecord = {
Id: string;
RepoTags: Array<string>;
Config: DockerInspectImageConfig,
RepoDigests: Array<string>;
Architecture: string;
Os: string;
Created: string;
User?: string;
};
function isDockerInspectImageConfig(maybeImageConfig: unknown): maybeImageConfig is DockerInspectImageConfig {
const imageConfig = maybeImageConfig as DockerInspectImageConfig;
if (!imageConfig || typeof imageConfig !== 'object') {
return false;
}
if (imageConfig.Env && !Array.isArray(imageConfig.Env)) {
return false;
}
if (imageConfig.Labels && typeof imageConfig.Labels !== 'object') {
return false;
}
if (imageConfig.ExposedPorts && typeof imageConfig.ExposedPorts !== 'object') {
return false;
}
if (imageConfig.Volumes && typeof imageConfig.Volumes !== 'object') {
return false;
}
if (imageConfig.WorkingDir && typeof imageConfig.WorkingDir !== 'string') {
return false;
}
if (imageConfig.User && typeof imageConfig.User !== 'string') {
return false;
}
if (imageConfig.Entrypoint && !Array.isArray(imageConfig.Entrypoint) && typeof imageConfig.Entrypoint !== 'string') {
return false;
}
if (imageConfig.Cmd && !Array.isArray(imageConfig.Cmd) && typeof imageConfig.Cmd !== 'string') {
return false;
}
return true;
}
export function isDockerInspectImageRecord(maybeImage: unknown): maybeImage is DockerInspectImageRecord {
const image = maybeImage as DockerInspectImageRecord;
if (!image || typeof image !== 'object') {
return false;
}
if (typeof image.Id !== 'string') {
return false;
}
if (!Array.isArray(image.RepoTags)) {
return false;
}
if (!isDockerInspectImageConfig(image.Config)) {
return false;
}
if (!Array.isArray(image.RepoDigests)) {
return false;
}
if (typeof image.Architecture !== 'string') {
return false;
}
if (typeof image.Os !== 'string') {
return false;
}
if (typeof image.Created !== 'string') {
return false;
}
return true;
}
export function normalizeDockerInspectImageRecord(image: DockerInspectImageRecord): InspectImagesItem {
// This is effectively doing firstOrDefault on the RepoTags for the image. If there are any values
// in RepoTags, the first one will be parsed and returned as the tag name for the image.
const imageNameInfo: ImageNameInfo = parseDockerLikeImageName(image.RepoTags?.[0]);
// Parse any environment variables defined for the image
const environmentVariables = parseDockerLikeEnvironmentVariables(image.Config?.Env || []);
// Parse any default ports exposed by the image
const ports = Object.entries(image.Config?.ExposedPorts || {}).map<PortBinding>(([rawPort]) => {
const [port, protocol] = rawPort.split('/');
return {
containerPort: parseInt(port),
protocol: protocol.toLowerCase() === 'tcp' ? 'tcp' : protocol.toLowerCase() === 'udp' ? 'udp' : undefined,
};
});
// Parse any default volumes specified by the image
const volumes = Object.entries(image.Config?.Volumes || {}).map<string>(([rawVolume]) => rawVolume);
// Parse any labels assigned to the image
const labels = image.Config?.Labels ?? {};
// Parse and normalize the image architecture
const architecture = image.Architecture?.toLowerCase() === 'amd64'
? 'amd64'
: image.Architecture?.toLowerCase() === 'arm64' ? 'arm64' : undefined;
// Parse and normalize the image OS
const os = image.Os?.toLowerCase() === 'linux'
? 'linux'
: image.Architecture?.toLowerCase() === 'windows'
? 'windows'
: undefined;
// Determine if the image has been pushed to a remote repo
// (no repo digests or only localhost/ repo digests)
const isLocalImage = !(image.RepoDigests || []).some((digest) => !digest.toLowerCase().startsWith('localhost/'));
return {
id: image.Id,
image: imageNameInfo,
repoDigests: image.RepoDigests,
isLocalImage,
environmentVariables,
ports,
volumes,
labels,
entrypoint: toArray(image.Config?.Entrypoint || []),
command: toArray(image.Config?.Cmd || []),
currentDirectory: image.Config?.WorkingDir || undefined,
architecture,
operatingSystem: os,
createdAt: dayjs(image.Created).toDate(),
user: image.Config?.User || undefined,
raw: JSON.stringify(image),
};
}

Просмотреть файл

@ -1,109 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { InspectNetworksItem, NetworkIpamConfig } from '../../contracts/ContainerClient';
import { dayjs } from '../../utils/dayjs';
export type DockerIpamConfig = {
Subnet: string;
Gateway: string;
};
export type DockerIpam = {
Driver: string;
Config: Array<DockerIpamConfig>;
};
export type DockerInspectNetworkRecord = {
Id: string;
Name: string;
Driver: string;
Scope: string;
Labels: Record<string, string>;
IPAM: DockerIpam;
EnableIPv6: boolean;
Internal: boolean;
Attachable: boolean;
Ingress: boolean;
Created: string;
};
export function isDockerInspectNetworkRecord(maybeNetwork: unknown): maybeNetwork is DockerInspectNetworkRecord {
const network = maybeNetwork as DockerInspectNetworkRecord;
if (!network || typeof network !== 'object') {
return false;
}
if (typeof network.Id !== 'string') {
return false;
}
if (typeof network.Name !== 'string') {
return false;
}
if (typeof network.Scope !== 'string') {
return false;
}
if (typeof network.Labels !== 'object') {
return false;
}
if (network.IPAM === null || typeof network.IPAM !== 'object' || typeof network.IPAM.Driver !== 'string') {
return false;
}
if (typeof network.EnableIPv6 !== 'boolean') {
return false;
}
if (typeof network.Internal !== 'boolean') {
return false;
}
if (typeof network.Attachable !== 'boolean') {
return false;
}
if (typeof network.Ingress !== 'boolean') {
return false;
}
if (typeof network.Created !== 'string') {
return false;
}
return true;
}
export function normalizeDockerInspectNetworkRecord(network: DockerInspectNetworkRecord): InspectNetworksItem {
const ipam: NetworkIpamConfig = {
driver: network.IPAM.Driver,
config: network.IPAM.Config.map(({ Subnet, Gateway }) => ({
subnet: Subnet,
gateway: Gateway,
})),
};
const createdAt = dayjs.utc(network.Created).toDate();
// Return the normalized InspectNetworksItem record
return {
id: network.Id,
name: network.Name,
driver: network.Driver,
scope: network.Scope,
labels: network.Labels || {},
ipam,
ipv6: network.EnableIPv6,
internal: network.Internal,
attachable: network.Attachable,
ingress: network.Ingress,
createdAt,
raw: JSON.stringify(network),
};
}

Просмотреть файл

@ -1,38 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { InspectVolumesItem } from '../../contracts/ContainerClient';
import { dayjs } from '../../utils/dayjs';
export type DockerInspectVolumeRecord = {
Name: string;
Driver: string;
Mountpoint: string;
Scope: string;
Labels: Record<string, string>;
Options: Record<string, unknown>;
CreatedAt: string;
};
// TODO: Actually test properties
export function isDockerInspectVolumeRecord(maybeVolume: unknown): maybeVolume is DockerInspectVolumeRecord {
return true;
}
export function normalizeDockerInspectVolumeRecord(volume: DockerInspectVolumeRecord): InspectVolumesItem {
const createdAt = dayjs.utc(volume.CreatedAt);
// Return the normalized InspectVolumesItem record
return {
name: volume.Name,
driver: volume.Driver,
mountpoint: volume.Mountpoint,
scope: volume.Scope,
labels: volume.Labels,
options: volume.Options,
createdAt: createdAt.toDate(),
raw: JSON.stringify(volume),
};
}

Просмотреть файл

@ -1,120 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ListContainersItem, PortBinding } from "../../contracts/ContainerClient";
import { dayjs } from '../../utils/dayjs';
import { parseDockerLikeImageName } from "./parseDockerLikeImageName";
import { parseDockerLikeLabels } from "./parseDockerLikeLabels";
import { parseDockerRawPortString } from "./parseDockerRawPortString";
export type DockerListContainerRecord = {
ID: string;
Names: string;
Image: string;
Ports: string;
Networks: string;
Labels: string;
CreatedAt: string;
State?: string;
Status: string;
};
export function isDockerListContainerRecord(maybeContainer: unknown): maybeContainer is DockerListContainerRecord {
const container = maybeContainer as DockerListContainerRecord;
if (!container || typeof container !== 'object') {
return false;
}
if (typeof container.ID !== 'string') {
return false;
}
if (typeof container.Names !== 'string') {
return false;
}
if (typeof container.Image !== 'string') {
return false;
}
if (typeof container.Ports !== 'string') {
return false;
}
if (typeof container.Networks !== 'string') {
return false;
}
if (typeof container.Labels !== 'string') {
return false;
}
if (typeof container.CreatedAt !== 'string') {
return false;
}
if (typeof container.Status !== 'string') {
return false;
}
return true;
}
export function normalizeDockerListContainerRecord(container: DockerListContainerRecord, strict: boolean): ListContainersItem {
const labels = parseDockerLikeLabels(container.Labels);
const ports = container.Ports
.split(',')
.map((port) => port.trim())
.filter((port) => !!port)
.reduce<Array<PortBinding>>((portBindings, rawPort) => {
const parsedPort = parseDockerRawPortString(rawPort);
if (parsedPort) {
return portBindings.concat(parsedPort);
} else if (strict) {
throw new Error('Invalid container JSON');
} else {
return portBindings;
}
}, []);
const networks = container.Networks
.split(',');
const name = container.Names.split(',')[0].trim();
const createdAt = dayjs.utc(container.CreatedAt).toDate();
return {
id: container.ID,
name,
labels,
image: parseDockerLikeImageName(container.Image),
ports,
networks,
createdAt,
state: normalizeContainerState(container),
status: container.Status,
};
}
// Exported just for tests, also why the typing is just a subset of the full record
export function normalizeContainerState(container: Pick<DockerListContainerRecord, 'State' | 'Status'>): string {
if (container.State) {
return container.State;
}
if (/paused/i.test(container.Status)) {
return 'paused';
} else if (/exit|terminate|dead/i.test(container.Status)) {
return 'exited';
} else if (/created/i.test(container.Status)) {
return 'created';
} else if (/up/i.test(container.Status)) {
return 'running';
}
return 'unknown';
}

Просмотреть файл

@ -1,62 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ListImagesItem } from '../../contracts/ContainerClient';
import { dayjs } from '../../utils/dayjs';
import { parseDockerLikeImageName } from './parseDockerLikeImageName';
import { tryParseSize } from './tryParseSize';
export type DockerListImageRecord = {
ID: string;
Repository: string;
Tag: string;
CreatedAt: string;
Size: string | number;
};
export function isDockerListImageRecord(maybeImage: unknown): maybeImage is DockerListImageRecord {
const image = maybeImage as DockerListImageRecord;
if (!image || typeof image !== 'object') {
return false;
}
if (typeof image.ID !== 'string') {
return false;
}
if (typeof image.Repository !== 'string') {
return false;
}
if (typeof image.Tag !== 'string') {
return false;
}
if (typeof image.CreatedAt !== 'string') {
return false;
}
if (typeof image.Size !== 'string' && typeof image.Size !== 'number') {
return false;
}
return true;
}
export function normalizeDockerListImageRecord(image: DockerListImageRecord): ListImagesItem {
const createdAt = dayjs.utc(image.CreatedAt).toDate();
const size = tryParseSize(image.Size);
const repositoryAndTag = `${image.Repository}${image.Tag ? `:${image.Tag}` : ''}`;
return {
id: image.ID,
image: parseDockerLikeImageName(repositoryAndTag),
// labels: {}, // TODO: image labels are conspicuously absent from Docker image listing output
createdAt,
size,
};
}

Просмотреть файл

@ -1,79 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ListNetworkItem } from '../../contracts/ContainerClient';
import { dayjs } from '../../utils/dayjs';
import { parseDockerLikeLabels } from './parseDockerLikeLabels';
export type DockerListNetworkRecord = {
ID: string;
Name: string;
Driver: string;
Labels: string;
Scope: string;
IPv6: string;
CreatedAt: string;
Internal: string;
};
export function isDockerListNetworkRecord(maybeNetwork: unknown): maybeNetwork is DockerListNetworkRecord {
const network = maybeNetwork as DockerListNetworkRecord;
if (!network || typeof network !== 'object') {
return false;
}
if (typeof network.ID !== 'string') {
return false;
}
if (typeof network.Name !== 'string') {
return false;
}
if (typeof network.Driver !== 'string') {
return false;
}
if (typeof network.Labels !== 'string') {
return false;
}
if (typeof network.Scope !== 'string') {
return false;
}
if (typeof network.IPv6 !== 'string') {
return false;
}
if (typeof network.CreatedAt !== 'string') {
return false;
}
if (typeof network.Internal !== 'string') {
return false;
}
return true;
}
export function normalizeDockerListNetworkRecord(network: DockerListNetworkRecord): ListNetworkItem {
// Parse the labels assigned to the networks and normalize to key value pairs
const labels = parseDockerLikeLabels(network.Labels);
const createdAt = dayjs.utc(network.CreatedAt).toDate();
return {
id: network.ID,
name: network.Name,
driver: network.Driver,
labels,
scope: network.Scope,
ipv6: network.IPv6.toLowerCase() === 'true',
internal: network.Internal.toLowerCase() === 'true',
createdAt,
};
}

Просмотреть файл

@ -1,23 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export type DockerVersionRecord = {
Client: { ApiVersion: string };
Server: { ApiVersion: string };
};
export function isDockerVersionRecord(maybeVersion: unknown): maybeVersion is DockerVersionRecord {
const version = maybeVersion as DockerVersionRecord;
if (typeof version?.Client?.ApiVersion !== 'string') {
return false;
}
if (typeof version?.Server?.ApiVersion !== 'string') {
return false;
}
return true;
}

Просмотреть файл

@ -1,44 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export type DockerVolumeRecord = {
Name: string;
Driver: string;
Labels: string;
Mountpoint: string;
Scope: string;
CreatedAt?: string;
Size?: string;
};
export function isDockerVolumeRecord(maybeVolume: unknown): maybeVolume is DockerVolumeRecord {
const volume = maybeVolume as DockerVolumeRecord;
if (!volume || typeof volume !== 'object') {
return false;
}
if (typeof volume.Name !== 'string') {
return false;
}
if (typeof volume.Driver !== 'string') {
return false;
}
if (typeof volume.Labels !== 'string') {
return false;
}
if (typeof volume.Mountpoint !== 'string') {
return false;
}
if (typeof volume.Scope !== 'string') {
return false;
}
return true;
}

Просмотреть файл

@ -1,26 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* Parse the standard Docker environment variable format into a key value record object
* @param environmentVariables A Docker like list of key=value environment variables
* @returns An object of key value pairs for the environment variables
*/
export function parseDockerLikeEnvironmentVariables(environmentVariables: Array<string>): Record<string, string> {
return environmentVariables.reduce<Record<string, string>>((evs, ev) => {
const index = ev.indexOf('=');
if (index > -1) {
const name = ev.slice(0, index);
const value = ev.slice(index + 1);
return {
...evs,
[name]: value,
};
}
return evs;
}, {});
}

Просмотреть файл

@ -1,55 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ImageNameInfo } from '../../contracts/ContainerClient';
/**
* A regex for parsing image names. Because this is only used to parse CLI output, we can assume
* the image names are valid.
*
* Registry: Everything before the first slash--must be either exactly "localhost", or contain a DNS
* separator "." or port separator ":". Port, if present, will also be included. If it does not meet
* these rules, it is not the registry but instead part of the image name. See
* https://stackoverflow.com/questions/37861791/how-are-docker-image-names-parsed.
*
* Image name: Everything after the registry (if the registry is valid) until the tag. Otherwise,
* everything until the tag.
*
* Tag: Everything after the ":", if it is present.
*/
const imageNameRegex = /^((?<registry>((localhost|([\w-]+(\.[\w-]+)+))(:\d+)?)|([\w-]+:\d+))\/)?(?<image>[\w-./<>]+)(:(?<tag>[\w-.<>]+))?(@(?<digest>.+))?$/;
// In certain cases, Docker makes image/tag names "<none>", which is not really valid. We will reinterpret those as `undefined`.
const noneImageName = /[<>]/i;
/**
* Parse an image name and return its components.
* @param originalName The original image name
* @returns The separated registry, image, and tag, along with the input original name
* and a verbose name composed of as much information as possible.
*/
export function parseDockerLikeImageName(originalName: string | undefined): ImageNameInfo {
if (!originalName) {
return {
originalName,
};
}
const match = imageNameRegex.exec(originalName);
if (!match || !match.groups) {
throw new Error('Invalid image name');
}
const { registry, image, tag, digest } = match.groups;
return {
originalName,
image: noneImageName.test(image) ? undefined : image,
tag: noneImageName.test(tag) ? undefined : tag,
digest,
registry,
};
}

Просмотреть файл

@ -1,19 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Labels } from "../../contracts/ContainerClient";
/**
* Parse Docker-like label string
* @param rawLabels Comma seperated string of labels
* @returns A {@link Labels} record
*/
export function parseDockerLikeLabels(rawLabels: string): Labels {
return rawLabels.split(',').reduce((labels, labelPair) => {
const index = labelPair.indexOf('=');
labels[labelPair.substring(0, index)] = labelPair.substring(index + 1);
return labels;
}, {} as Labels);
}

Просмотреть файл

@ -1,36 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { PortBinding } from "../../contracts/ContainerClient";
/**
* Attempt to parse a Docker-like raw port binding string
* @param portString the raw port string to parse, e.g. "1234/tcp" or "0.0.0.0:1234->1234/udp"
* @returns Parsed raw port string as a PortBinding record or undefined if invalid
*/
export function parseDockerRawPortString(portString: string): PortBinding | undefined {
const portRegex = /((?<hostIp>[\da-f.:[\]]+)(:(?<hostPort>\d+)))?(\s*->\s*)?((?<containerPort>\d+)\/(?<protocol>tcp|udp))/i;
const result = portRegex.exec(portString);
if (!result || !result.groups) {
return undefined;
}
const hostIp = result.groups['hostIp'] || undefined;
const hostPort = result.groups['hostPort'] ? Number.parseInt(result.groups['hostPort']) : undefined;
const containerPort = result.groups['containerPort'] ? Number.parseInt(result.groups['containerPort']) : undefined;
const protocol = result.groups['protocol'] || undefined;
if (containerPort === undefined || (protocol !== 'tcp' && protocol !== 'udp')) {
return undefined;
}
return {
hostIp,
hostPort,
containerPort,
protocol,
};
}

Просмотреть файл

@ -1,133 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as path from 'path';
import * as vscode from 'vscode';
import { ListFilesCommandOptions, ListFilesItem } from '../../contracts/ContainerClient';
import { dayjs } from '../../utils/dayjs';
const DateFormats = [
'MMM D HH:mm', // Linux format
'MMM D YYYY', // Linux format for last year
'MM/DD/YYYY hh:mm A', // Windows format
];
const SupportedFileTypes = [vscode.FileType.Directory, vscode.FileType.File];
type FileMode = {
mode?: number;
fileType: vscode.FileType;
};
export function parseListFilesCommandLinuxOutput(
options: ListFilesCommandOptions,
output: string
): ListFilesItem[] {
const regex = /^(?<type>[0-9a-fA-F]+)\s+(?<links>\d+)\s+(?<group>\d+)\s+(?<owner>\d+)\s+(?<size>\d+)\s+(?<atime>\d+)\s+(?<mtime>\d+)\s+(?<ctime>\d+)\s+(?<name>.*)$/gm;
const items = new Array<ListFilesItem>();
for (const match of output.matchAll(regex)) {
/* eslint-disable @typescript-eslint/no-non-null-assertion */
const name = path.basename(match.groups!.name);
const { mode, fileType } = parseLinuxType(match.groups!.type);
const size = Number.parseInt(match.groups!.size, 10);
const mtime = dayjs.unix(Number.parseInt(match.groups!.mtime, 10)).valueOf();
const ctime = dayjs.unix(Number.parseInt(match.groups!.ctime, 10)).valueOf();
const atime = dayjs.unix(Number.parseInt(match.groups!.atime, 10)).valueOf();
/* eslint-enable @typescript-eslint/no-non-null-assertion */
// Ignore relative directory items...
if (fileType === vscode.FileType.Directory && (name === '.' || name === '..')) {
continue;
}
// Ignore everything other than directories and plain files
if (!SupportedFileTypes.includes(fileType)) {
continue;
}
items.push({
name,
path: path.posix.join(options.path, name),
type: fileType,
mode,
ctime,
mtime,
atime,
size,
});
}
return items;
}
export function parseListFilesCommandWindowsOutput(
options: ListFilesCommandOptions,
output: string
): ListFilesItem[] {
const regex = /^(?<mtime>(?<date>\d{1,2}(\/|\.)\d{1,2}(\/|\.)\d{4})\s+(?<time>\d{1,2}:\d{1,2}( (AM|PM))?))\s+((?<type><DIR>|<SYMLINKD>)|(?<size>\d+))\s+(?<name>.*)$/gm;
const items = new Array<ListFilesItem>();
for (const match of output.matchAll(regex)) {
/* eslint-disable @typescript-eslint/no-non-null-assertion */
const name = match.groups!.name;
const fileType = parseWindowsType(match.groups!.type);
const size = fileType === vscode.FileType.Directory ? 0 : Number.parseInt(match.groups!.size, 10);
const mtime = dayjs(match.groups!.mtime, DateFormats).valueOf();
/* eslint-enable @typescript-eslint/no-non-null-assertion */
// Ignore relative directory items...
if (fileType === vscode.FileType.Directory && (name === '.' || name === '..')) {
continue;
}
// Ignore everything other than directories and plain files
if (!SupportedFileTypes.includes(fileType)) {
return items;
}
items.push({
name,
path: path.win32.join(options.path, name),
type: fileType,
mtime,
size,
});
}
return items;
}
function parseLinuxType(fullModeHex: string): FileMode {
const fullMode = parseInt(fullModeHex, 16);
const fileType = (fullMode & 0xf000) >> 12;
const mode = fullMode & 0xfff;
switch (fileType) {
case 4:
return { mode, fileType: vscode.FileType.Directory };
case 8:
return { mode, fileType: vscode.FileType.File };
case 10:
return { mode, fileType: vscode.FileType.SymbolicLink };
default:
return { mode, fileType: vscode.FileType.Unknown };
}
}
function parseWindowsType(type: string | undefined): vscode.FileType {
switch (type?.toUpperCase()) {
case '<DIR>':
return vscode.FileType.Directory;
case '':
case undefined:
// Blank or undefined type is a file
return vscode.FileType.File;
case '<SYMLINKD>':
case '<SYMLINK>':
return vscode.FileType.SymbolicLink;
default:
return vscode.FileType.Unknown;
}
}

Просмотреть файл

@ -1,43 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* Tries to parse a size (in many forms) into a value in bytes
* @param value The value to try to parse into a size
* @returns An integer value in bytes, if the input can be parsed, otherwise undefined
*/
export function tryParseSize(value: string | number | undefined | null): number | undefined {
if (value === undefined || value === null) {
return undefined;
} else if (typeof value === 'number') {
return Math.round(value);
} else {
if (value.toLowerCase() === 'n/a') {
return undefined;
} else {
// Parses values like "1234", "1234b", "1234kb", "1234 MB", "12.34 GB" etc. into size (the numerical part)
// and sizeUnit (the kb/mb/gb, if present)
const result = /(?<size>\d+(\.\d+)?)\s*(?<sizeUnit>[kmg]?b)?/i.exec(value);
if (result?.groups?.size) {
const size: number = Number.parseFloat(result.groups.size);
const unit: string | undefined = result.groups.sizeUnit;
switch (unit?.toLowerCase()) {
case 'kb':
return Math.round(size * 1024);
case 'mb':
return Math.round(size * 1024 * 1024);
case 'gb':
return Math.round(size * 1024 * 1024 * 1024);
default:
return Math.round(size);
}
} else {
return undefined;
}
}
}
}

Просмотреть файл

@ -1,11 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ReadFileCommandOptions, WriteFileCommandOptions } from "../../contracts/ContainerClient";
import { CommandLineCurryFn, withArg } from "../../utils/commandLineBuilder";
export function withContainerPathArg(options: ReadFileCommandOptions | WriteFileCommandOptions): CommandLineCurryFn {
return withArg(`${options.container}:${options.path}`);
}

Просмотреть файл

@ -1,15 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { RunContainerExtraHost } from "../../contracts/ContainerClient";
import { withNamedArg } from "../../utils/commandLineBuilder";
export function formatAddHost(addHost: RunContainerExtraHost): string {
return `${addHost.hostname}:${addHost.ip}`;
}
export function withDockerAddHostArg(addHosts?: Array<RunContainerExtraHost>) {
return withNamedArg('--add-host', (addHosts || []).map(formatAddHost));
}

Просмотреть файл

@ -1,10 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { withNamedArg } from "../../utils/commandLineBuilder";
export function withDockerBuildArg(buildArgs?: Record<string, string>) {
return withNamedArg('--build-arg', Object.entries(buildArgs || {}).map(([key, value]) => `${key}=${value}`));
}

Просмотреть файл

@ -1,10 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { withNamedArg } from "../../utils/commandLineBuilder";
export function withDockerEnvArg(env?: Record<string, string>) {
return withNamedArg('--env', Object.entries(env || {}).map(([key, value]) => `${key}=${value}`));
}

Просмотреть файл

@ -1,10 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { withNamedArg } from "../../utils/commandLineBuilder";
export function withDockerExposePortsArg(ports?: Array<number>) {
return withNamedArg('--expose', (ports || []).map(port => port.toString()), { shouldQuote: false });
}

Просмотреть файл

@ -1,15 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ShellQuotedString } from 'vscode';
import { CommandLineCurryFn, withNamedArg } from '../../utils/commandLineBuilder';
export function withDockerFilterArg(filter: string | ShellQuotedString | (string | ShellQuotedString | null | undefined)[] | null | undefined): CommandLineCurryFn {
return withNamedArg('--filter', filter);
}
export function withDockerBooleanFilterArg(filter: string, value: boolean | null | undefined): CommandLineCurryFn {
return withDockerFilterArg(typeof value === 'boolean' ? `${filter}=${value}` : undefined);
}

Просмотреть файл

@ -1,8 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { withNamedArg } from '../../utils/commandLineBuilder';
export const withDockerIgnoreSizeArg = withNamedArg('--size','false', { assignValue: true, shouldQuote: false });

Просмотреть файл

@ -1,8 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { withNamedArg } from '../../utils/commandLineBuilder';
export const withDockerJsonFormatArg = withNamedArg('--format', '{{json .}}');

Просмотреть файл

@ -1,24 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { LabelFilters } from "../../contracts/ContainerClient";
import { conditional } from "../../utils/conditional";
import { withDockerFilterArg } from "./withDockerFilterArg";
export function formatDockerLabelFilter(name: string, value: boolean | string): string | undefined {
if (typeof value === 'boolean' && value) {
return `label=${name}`;
} else if (typeof value === 'string') {
return conditional`label=${name}=${value}`;
}
return undefined;
}
export function withDockerLabelFilterArgs(labels?: LabelFilters) {
return withDockerFilterArg(
Object.entries(labels || {}).map(([label, value]) => formatDockerLabelFilter(label, value)),
);
}

Просмотреть файл

@ -1,14 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Labels } from "../../contracts/ContainerClient";
import { withNamedArg } from "../../utils/commandLineBuilder";
export function withDockerLabelsArg(labels?: Labels) {
return withNamedArg(
'--label',
Object.entries(labels || {}).map(([label, value]) => `${label}=${value}`),
);
}

Просмотреть файл

@ -1,22 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { RunContainerMount } from "../../contracts/ContainerClient";
import { withNamedArg } from "../../utils/commandLineBuilder";
export function formatDockerMount(mount: RunContainerMount): string {
const mountParts = new Array<string>(
`type=${mount.type}`,
`source=${mount.source}`,
`destination=${mount.destination}`,
mount.readOnly ? 'readonly' : '',
);
return mountParts.filter((part) => !!part).join(',');
}
export function withDockerMountsArg(mounts?: Array<RunContainerMount>) {
return withNamedArg('--mount', (mounts || []).map(formatDockerMount));
}

Просмотреть файл

@ -1,8 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { withArg } from "../../utils/commandLineBuilder";
export const withDockerNoTruncArg = withArg('--no-trunc');

Просмотреть файл

@ -1,36 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ContainerPlatform } from "../../contracts/ContainerClient";
import { withNamedArg } from "../../utils/commandLineBuilder";
import { getNativeArchitecture } from "../../utils/getNativeArchitecture";
import { normalizeContainerOS } from "../../utils/normalizeContainerOS";
export function formatDockerPlatform(platform: ContainerPlatform): string | undefined {
if (!platform?.os && !platform?.architecture) {
return undefined;
}
const os = normalizeContainerOS(platform?.os);
const architecture = platform?.architecture || getNativeArchitecture();
return `${os}/${architecture}`;
}
/**
* This method formats the `platform` flag for the Docker CLI.
*
* The `os` and `architecture` properties are extracted and used to create a new `ContainerPlatform`
* object. If either property is missing, a default value ofp `'linux'` for `os` or the result of
* `getNativeArchitecture()` for `architecture` is used.
*
* If an empty object is passed in, `undefined` is returned, which will allow the Docker CLI to
* skip the `--platform` flag entirely and use the default platform.
*
* @param platform
* @returns
*/
export function withDockerPlatformArg(platform: ContainerPlatform) {
return withNamedArg('--platform', formatDockerPlatform(platform));
}

Просмотреть файл

@ -1,22 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { PortBinding } from "../../contracts/ContainerClient";
import { withNamedArg } from "../../utils/commandLineBuilder";
export function withDockerPortsArg(ports?: Array<PortBinding>) {
return withNamedArg(
'--publish',
(ports || []).map((port) => {
let binding = port.hostIp ? `${port.hostIp}:` : '';
binding += `${port.hostPort || ''}:`;
binding += port.containerPort;
if (port.protocol) {
binding += `/${port.protocol}`;
}
return binding;
}),
);
}

Просмотреть файл

@ -1,280 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { GeneratorCommandResponse, PromiseCommandResponse, VoidCommandResponse } from '../../contracts/CommandRunner';
import {
CommonOrchestratorCommandOptions,
ConfigCommandOptions,
ConfigItem,
DownCommandOptions,
IContainerOrchestratorClient,
LogsCommandOptions,
RestartCommandOptions,
StartCommandOptions,
StopCommandOptions,
UpCommandOptions,
} from '../../contracts/ContainerOrchestratorClient';
import {
CommandLineArgs,
CommandLineCurryFn,
composeArgs,
withArg,
withFlagArg,
withNamedArg,
withVerbatimArg,
} from '../../utils/commandLineBuilder';
import { stringStreamToGenerator } from '../../utils/streamToGenerator';
import { ConfigurableClient } from '../ConfigurableClient';
function withCommonOrchestratorArgs(options: CommonOrchestratorCommandOptions): CommandLineCurryFn {
return composeArgs(
withNamedArg('--file', options.files),
withNamedArg('--env-file', options.environmentFile),
withNamedArg('--project-name', options.projectName),
);
}
function withComposeArg(composeV2: boolean): CommandLineCurryFn {
// If using Compose V2, then add the `compose` argument at the beginning
// That way, the command is `docker compose` instead of `docker-compose`
return withArg(composeV2 ? 'compose' : undefined);
}
export class DockerComposeClient extends ConfigurableClient implements IContainerOrchestratorClient {
/**
* The ID of the Docker Compose client
*/
public static ClientId = 'com.microsoft.visualstudio.orchestrators.dockercompose';
/**
* Constructs a new {@link DockerComposeClient}
* @param commandName (Optional, default `docker`) The command that will be run
* as the base command. If quoting is necessary, it is the responsibility of the
* caller to add.
* @param displayName (Optional, default 'Docker Compose') The human-friendly display
* name of the client
* @param description (Optional, with default) The human-friendly description of
* the client
* @param composeV2 (Optional, default `true`) If true, `compose` will be added as the
* first argument to all commands. The base command should be `docker`.
*/
public constructor(
commandName?: string,
displayName: string = 'Docker Compose',
description: string = 'Runs orchestrator commands using the Docker Compose CLI',
composeV2: boolean = true
) {
super(
DockerComposeClient.ClientId,
commandName || composeV2 ? 'docker' : 'docker-compose',
displayName,
description
);
this.#composeV2 = composeV2;
}
#composeV2: boolean;
public get composeV2(): boolean {
return this.#composeV2;
}
public set composeV2(value: boolean) {
this.#composeV2 = value;
}
//#region Up command
protected getUpCommandArgs(options: UpCommandOptions): CommandLineArgs {
return composeArgs(
withComposeArg(this.composeV2),
withCommonOrchestratorArgs(options),
withNamedArg('--profile', options.profiles),
withArg('up'),
withFlagArg('--detach', options.detached),
withFlagArg('--build', options.build),
withNamedArg('--scale', Object.entries(options.scale || {}).map(([service, scale]) => `${service}=${scale}`)),
withNamedArg('--timeout', options.timeoutSeconds?.toString(10)),
withFlagArg('--wait', options.wait),
withVerbatimArg(options.customOptions),
withArg(...(options.services || [])),
)();
}
/**
* Generates the necessary information for running of an orchestrator up command for Docker Compose
* @param options Standard orchestrator up command options
* @returns A CommandResponse indicating how to run an orchestrator up command for Docker Compose
*/
public async up(options: UpCommandOptions): Promise<VoidCommandResponse> {
return {
command: this.commandName,
args: this.getUpCommandArgs(options),
};
}
//#endregion Up command
//#region Down command
protected getDownCommandArgs(options: DownCommandOptions): CommandLineArgs {
return composeArgs(
withComposeArg(this.composeV2),
withCommonOrchestratorArgs(options),
withArg('down'),
withNamedArg('--rmi', options.removeImages),
withFlagArg('--volumes', options.removeVolumes),
withNamedArg('--timeout', options.timeoutSeconds?.toString(10)),
withVerbatimArg(options.customOptions),
)();
}
/**
* Generates the necessary information for running of an orchestrator down command for Docker Compose
* @param options Standard orchestrator down command options
* @returns A CommandResponse indicating how to run an orchestrator down command for Docker Compose
*/
public async down(options: DownCommandOptions): Promise<VoidCommandResponse> {
return {
command: this.commandName,
args: this.getDownCommandArgs(options),
};
}
//#endregion Down command
//#region Start command
protected getStartCommandArgs(options: StartCommandOptions): CommandLineArgs {
return composeArgs(
withComposeArg(this.composeV2),
withCommonOrchestratorArgs(options),
withArg('start'),
)();
}
/**
* Generates the necessary information for running of an orchestrator start command for Docker Compose
* @param options Standard orchestrator start command options
* @returns A CommandResponse indicating how to run an orchestrator start command for Docker Compose
*/
public async start(options: StartCommandOptions): Promise<VoidCommandResponse> {
return {
command: this.commandName,
args: this.getStartCommandArgs(options),
};
}
//#endregion Start command
//#region Stop command
protected getStopCommandArgs(options: StopCommandOptions): CommandLineArgs {
return composeArgs(
withComposeArg(this.composeV2),
withCommonOrchestratorArgs(options),
withArg('stop'),
withNamedArg('--timeout', options.timeoutSeconds?.toString(10)),
)();
}
/**
* Generates the necessary information for running of an orchestrator stop command for Docker Compose
* @param options Standard orchestrator stop command options
* @returns A CommandResponse indicating how to run an orchestrator stop command for Docker Compose
*/
public async stop(options: StopCommandOptions): Promise<VoidCommandResponse> {
return {
command: this.commandName,
args: this.getStopCommandArgs(options),
};
}
//#endregion Stop command
//#region Restart command
protected getRestartCommandArgs(options: RestartCommandOptions): CommandLineArgs {
return composeArgs(
withComposeArg(this.composeV2),
withCommonOrchestratorArgs(options),
withArg('restart'),
withNamedArg('--timeout', options.timeoutSeconds?.toString(10)),
)();
}
/**
* Generates the necessary information for running of an orchestrator restart command for Docker Compose
* @param options Standard orchestrator restart command options
* @returns A CommandResponse indicating how to run an orchestrator restart command for Docker Compose
*/
public async restart(options: RestartCommandOptions): Promise<VoidCommandResponse> {
return {
command: this.commandName,
args: this.getRestartCommandArgs(options),
};
}
//#endregion Restart command
//#region Logs command
protected getLogsCommandArgs(options: LogsCommandOptions): CommandLineArgs {
return composeArgs(
withComposeArg(this.composeV2),
withCommonOrchestratorArgs(options),
withArg('logs'),
withFlagArg('--follow', options.follow),
withNamedArg('--tail', options.tail?.toString(10)),
)();
}
/**
* Generates the necessary information for running of an orchestrator logs command for Docker Compose
* @param options Standard orchestrator logs command options
* @returns A CommandResponse indicating how to run an orchestrator logs command for Docker Compose
*/
public async logs(options: LogsCommandOptions): Promise<GeneratorCommandResponse<string>> {
return {
command: this.commandName,
args: this.getLogsCommandArgs(options),
parseStream: (output, strict) => stringStreamToGenerator(output),
};
}
//#endregion Logs command
//#region Config command
protected getConfigCommandArgs(options: ConfigCommandOptions): CommandLineArgs {
return composeArgs(
withComposeArg(this.composeV2),
withCommonOrchestratorArgs(options),
withArg('config'),
withArg(`--${options.configType}`),
)();
}
protected async parseConfigCommandOutput(
output: string,
strict: boolean,
): Promise<Array<ConfigItem>> {
return output.split('\n').filter((config) => config);
}
/**
* Generates the necessary information for running of an orchestrator config command for Docker Compose
* @param options Standard orchestrator config command options
* @returns A CommandResponse indicating how to run an orchestrator config command for Docker Compose
*/
public async config(options: ConfigCommandOptions): Promise<PromiseCommandResponse<Array<ConfigItem>>> {
return {
command: this.commandName,
args: this.getConfigCommandArgs(options),
parse: this.parseConfigCommandOutput,
};
}
//#endregion Config command
}

Просмотреть файл

@ -1,118 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as stream from 'stream';
import {
CommandResponseBase,
CommandRunner,
GeneratorCommandResponse,
ICommandRunnerFactory,
Like,
normalizeCommandResponseLike,
PromiseCommandResponse,
StreamingCommandRunner,
VoidCommandResponse,
} from '../contracts/CommandRunner';
import { CancellationTokenLike } from '../typings/CancellationTokenLike';
import { AccumulatorStream } from '../utils/AccumulatorStream';
import { CancellationError } from '../utils/CancellationError';
import { CommandLineArgs } from '../utils/commandLineBuilder';
import {
spawnStreamAsync,
StreamSpawnOptions,
} from '../utils/spawnStreamAsync';
export type ShellStreamCommandRunnerOptions = StreamSpawnOptions & {
strict?: boolean;
};
/**
* A {@link CommandRunnerFactory} that executes commands on a given shell and
* manages access to the necessary stdio streams
*/
export class ShellStreamCommandRunnerFactory<TOptions extends ShellStreamCommandRunnerOptions> implements ICommandRunnerFactory {
public constructor(protected readonly options: TOptions) { }
public getCommandRunner(): CommandRunner {
return async <T>(commandResponseLike: Like<VoidCommandResponse> | Like<PromiseCommandResponse<T>>) => {
const commandResponse = await normalizeCommandResponseLike(commandResponseLike);
const { command, args } = this.getCommandAndArgs(commandResponse);
throwIfCancellationRequested(this.options.cancellationToken);
let result: T | undefined;
let accumulator: AccumulatorStream | undefined;
try {
if (commandResponse.parse) {
accumulator = new AccumulatorStream();
}
// Determine the appropriate combination of streams that need to read from stdout
let stdOutPipe: NodeJS.WritableStream | undefined = accumulator;
if (accumulator && this.options.stdOutPipe) {
const stdOutPassThrough = new stream.PassThrough();
stdOutPassThrough.pipe(this.options.stdOutPipe);
stdOutPassThrough.pipe(accumulator);
stdOutPipe = stdOutPassThrough;
} else if (this.options.stdOutPipe) {
stdOutPipe = this.options.stdOutPipe;
}
await spawnStreamAsync(command, args, { ...this.options, stdOutPipe: stdOutPipe });
throwIfCancellationRequested(this.options.cancellationToken);
if (accumulator && commandResponse.parse) {
const output = await accumulator.getString();
throwIfCancellationRequested(this.options.cancellationToken);
result = await commandResponse.parse(output, !!this.options.strict);
}
throwIfCancellationRequested(this.options.cancellationToken);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return result!;
} finally {
accumulator?.destroy();
}
};
}
public getStreamingCommandRunner(): StreamingCommandRunner {
return this.streamingCommandRunner.bind(this);
}
private async *streamingCommandRunner<T>(commandResponseLike: Like<GeneratorCommandResponse<T>>): AsyncGenerator<T> {
const commandResponse = await normalizeCommandResponseLike(commandResponseLike);
const { command, args } = this.getCommandAndArgs(commandResponse);
throwIfCancellationRequested(this.options.cancellationToken);
const dataStream: stream.PassThrough = new stream.PassThrough();
const innerGenerator = commandResponse.parseStream(dataStream, !!this.options.strict);
// The process promise will be awaited only after the innerGenerator finishes
const processPromise = spawnStreamAsync(command, args, { ...this.options, stdOutPipe: dataStream });
for await (const element of innerGenerator) {
yield element;
}
await processPromise;
}
protected getCommandAndArgs(commandResponse: CommandResponseBase): { command: string, args: CommandLineArgs } {
return commandResponse;
}
}
function throwIfCancellationRequested(token?: CancellationTokenLike): void {
if (token?.isCancellationRequested) {
throw new CancellationError('Command cancelled', token);
}
}

Просмотреть файл

@ -1,36 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import {
CommandResponseBase,
ICommandRunnerFactory,
} from '../contracts/CommandRunner';
import { CommandLineArgs, composeArgs, withArg, withNamedArg } from '../utils/commandLineBuilder';
import {
ShellStreamCommandRunnerFactory,
ShellStreamCommandRunnerOptions,
} from './shellStream';
export type WslShellCommandRunnerOptions = ShellStreamCommandRunnerOptions & {
wslPath?: string;
distro?: string | null;
};
/**
* Special case of {@link ShellStreamCommandRunnerFactory} for executing commands in a wsl distro
*/
export class WslShellCommandRunnerFactory extends ShellStreamCommandRunnerFactory<WslShellCommandRunnerOptions> implements ICommandRunnerFactory {
protected getCommandAndArgs(commandResponse: CommandResponseBase): { command: string, args: CommandLineArgs } {
const command = this.options.wslPath ?? 'wsl.exe';
const args = composeArgs(
withNamedArg('-d', this.options.distro),
withArg('--'),
withArg(commandResponse.command),
withArg(...commandResponse.args),
)();
return { command, args };
}
}

Просмотреть файл

@ -1,76 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CommandLineArgs } from '../utils/commandLineBuilder';
/**
* A command response includes the command (i.e., the executable) to execute, and arguments to pass
*/
export type CommandResponseBase = {
command: string;
args: CommandLineArgs;
};
/**
* A {@link CommandResponseBase} that also includes a method to parse the output of the command
*/
export type PromiseCommandResponse<T> = CommandResponseBase & {
parse: (output: string, strict: boolean) => Promise<T>;
};
/**
* A {@link CommandResponseBase} that also includes a method to parse streaming output of the command
* as an {@link AsyncGenerator}
*/
export type GeneratorCommandResponse<T> = CommandResponseBase & {
parseStream: (output: NodeJS.ReadableStream, strict: boolean) => AsyncGenerator<T>;
};
/**
* A {@link CommandResponseBase} that cannot include parsing methods--i.e. the output is `void`
*/
export type VoidCommandResponse = CommandResponseBase & {
parse?: never;
parseStream?: never;
};
/**
* A helper type that allows for several simple ways to resolve an item
*/
export type Like<T> = T | Promise<T> | (() => T | Promise<T>);
/**
* A {@link CommandRunner} provides instructions on how to invoke a command
*/
export type CommandRunner =
(<T>(commandResponseLike: Like<PromiseCommandResponse<T>>) => Promise<T>) &
((commandResponseLike: Like<VoidCommandResponse>) => Promise<void>);
/**
* A {@link StreamingCommandRunner} provides instructions on how to invoke a streaming command
*/
export type StreamingCommandRunner = <T>(commandResponseLike: Like<GeneratorCommandResponse<T>>) => AsyncGenerator<T>;
/**
* A {@link ICommandRunnerFactory} is used to build a CommandRunner instance
* based for a specific configuration
*/
export interface ICommandRunnerFactory {
getCommandRunner(): CommandRunner;
getStreamingCommandRunner(): StreamingCommandRunner;
}
/**
* Converts a `Like<CommandResponse>` into a `CommandResponse`
* @param commandResponseLike The command response-like to normalize
* @returns The command response
*/
export function normalizeCommandResponseLike<TCommandResponse extends CommandResponseBase>(commandResponseLike: Like<TCommandResponse>): Promise<TCommandResponse> {
if (typeof commandResponseLike === 'function') {
return Promise.resolve(commandResponseLike());
} else {
return Promise.resolve(commandResponseLike);
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,192 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { GeneratorCommandResponse, PromiseCommandResponse, VoidCommandResponse } from "./CommandRunner";
import { ClientIdentity, CommonCommandOptions } from "./ContainerClient";
// #region Container orchestrator commands
// Common command options
export type CommonOrchestratorCommandOptions = CommonCommandOptions & {
/**
* Orchestrator files, e.g. compose files
*/
files?: Array<string>;
/**
* Environment variable file
*/
environmentFile?: string;
/**
* Project name
*/
projectName?: string;
};
// Up command types
export type UpCommandOptions = CommonOrchestratorCommandOptions & {
/**
* Whether to build while up'ing
*/
build?: boolean;
/**
* Whether to run in a detached session
*/
detached?: boolean;
/**
* A timeout in seconds
*/
timeoutSeconds?: number;
/**
* Whether to wait until services are running and healthy
*/
wait?: boolean;
/**
* Specific services to start
*/
services?: Array<string>;
/**
* Specific service profiles to start
*/
profiles?: Array<string>;
/**
* Override specific service scaling
*/
scale?: Record<string, number>;
/**
* Additional custom options to pass
*/
customOptions?: string;
};
type UpCommand = {
/**
* Generate a {@link VoidCommandResponse} for up'ing services with a container orchestrator
* @param options Command options
*/
up(options: UpCommandOptions): Promise<VoidCommandResponse>;
};
// Down command types
export type DownCommandOptions = CommonOrchestratorCommandOptions & {
/**
* Whether to remove named volumes
*/
removeVolumes?: boolean;
/**
* Whether to remove images
*/
removeImages?: 'all' | 'local';
/**
* A timeout in seconds
*/
timeoutSeconds?: number;
/**
* Additional custom options to pass
*/
customOptions?: string;
};
type DownCommand = {
/**
* Generate a {@link VoidCommandResponse} for down'ing services with a container orchestrator
* @param options Command options
*/
down(options: DownCommandOptions): Promise<VoidCommandResponse>;
};
// Start command types
// No special options
export type StartCommandOptions = CommonOrchestratorCommandOptions;
type StartCommand = {
/**
* Generate a {@link VoidCommandResponse} for starting services with a container orchestrator
* @param options Command options
*/
start(options: StartCommandOptions): Promise<VoidCommandResponse>;
};
// Stop command types
export type StopCommandOptions = CommonOrchestratorCommandOptions & {
/**
* A timeout in seconds
*/
timeoutSeconds?: number;
};
type StopCommand = {
/**
* Generate a {@link VoidCommandResponse} for stopping services with a container orchestrator
* @param options Command options
*/
stop(options: StopCommandOptions): Promise<VoidCommandResponse>;
};
// Restart command types
export type RestartCommandOptions = CommonOrchestratorCommandOptions & {
/**
* A timeout in seconds
*/
timeoutSeconds?: number;
};
type RestartCommand = {
/**
* Generate a {@link VoidCommandResponse} for restarting services with a container orchestrator
* @param options Command options
*/
restart(options: RestartCommandOptions): Promise<VoidCommandResponse>;
};
// Logs command types
export type LogsCommandOptions = CommonOrchestratorCommandOptions & {
/**
* Whether or not to follow the log output
*/
follow?: boolean;
/**
* Maximum number of lines to show from the end of the logs
*/
tail?: number;
};
type LogsCommand = {
/**
* Generate a {@link GeneratorCommandResponse} for getting collated logs from services with a container orchestrator
* @param options Command options
*/
logs(options: LogsCommandOptions): Promise<GeneratorCommandResponse<string>>;
};
// Config command types
export type ConfigCommandOptions = CommonOrchestratorCommandOptions & {
configType: 'services' | 'images' | 'profiles' | 'volumes';
};
// The output is just a simple string
export type ConfigItem = string;
type ConfigCommand = {
/**
* Generate a {@link PromiseCommandResponse} for getting config information for services
* @param options Command options
*/
config(options: ConfigCommandOptions): Promise<PromiseCommandResponse<Array<ConfigItem>>>;
};
// #endregion
/**
* Standard interface for executing commands against container runtimes.
* Individual runtimes implement this interface.
*/
export interface IContainerOrchestratorClient extends
ClientIdentity,
UpCommand,
DownCommand,
StartCommand,
StopCommand,
RestartCommand,
LogsCommand,
ConfigCommand { }

Просмотреть файл

@ -1,13 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ShellQuotedString, ShellQuoting } from 'vscode';
import { CommandLineArgs } from '../utils/commandLineBuilder';
export interface IShell {
quote(args: CommandLineArgs): Array<string>;
goTemplateQuotedString(arg: string, quoting: ShellQuoting): ShellQuotedString;
getShellOrDefault(shell?: string | boolean): string | boolean | undefined;
}

Просмотреть файл

@ -1,23 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export * from './clients/DockerClient/DockerClient';
export * from './clients/DockerComposeClient/DockerComposeClient';
export * from './commandRunners/shellStream';
export * from './commandRunners/wslStream';
export * from './contracts/CommandRunner';
export * from './contracts/ContainerClient';
export * from './contracts/ContainerOrchestratorClient';
export * from './typings/CancellationTokenLike';
export * from './typings/DisposableLike';
export * from './typings/EventLike';
export * from './utils/AccumulatorStream';
export * from './utils/CancellationError';
export * from './utils/ChildProcessError';
export * from './utils/CommandNotSupportedError';
export * from './utils/commandLineBuilder';
export * from './utils/getNativeArchitecture';
export * from './utils/normalizeContainerOS';
export * from './utils/spawnStreamAsync';

Просмотреть файл

@ -1,135 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { expect } from 'chai';
import * as crypto from 'crypto';
import { describe, it } from 'mocha';
import { ShellQuoting } from 'vscode';
import {
DockerClient,
} from '../clients/DockerClient/DockerClient';
import { BuildImageCommandOptions, RunContainerCommandOptions } from '../contracts/ContainerClient';
import { escaped } from '../utils/commandLineBuilder';
import { Bash, Powershell } from '../utils/spawnStreamAsync';
describe('DockerClient', () => {
const client = new DockerClient();
describe('#listImagesAsync()', () => {
it('parses date formats', async () => {
const commandResult = await client.listImages({});
const results = await commandResult.parse(
[
'{"Containers":"N/A","CreatedAt":"2021-06-08 08:07:21 +0100 BST","CreatedSince":"17 months ago","Digest":"\u003cnone\u003e","ID":"someid","Repository":"some/repository","SharedSize":"N/A","Size":"1MB","Tag":"sometag","UniqueSize":"N/A","VirtualSize":"1MB"}',
'{"Containers":"N/A","CreatedAt":"2021-06-08 08:07:21.000Z","CreatedSince":"17 months ago","Digest":"\u003cnone\u003e","ID":"otherid","Repository":"some/repository","SharedSize":"N/A","Size":"1MB","Tag":"sometag","UniqueSize":"N/A","VirtualSize":"1MB"}',
].join('\n'),
false,
);
expect(results).to.have.lengthOf(2);
expect(results[0]).to.have.property('createdAt');
expect(results[0].createdAt.getDay()).to.not.be.NaN;
expect(results[1]).to.have.property('createdAt');
expect(results[1].createdAt.getDay()).to.not.be.NaN;
});
});
describe('#buildImageAsync()', () => {
it('handles default values', async () => {
const path = crypto.randomBytes(60).toString('utf8');
const commandResult = await client.buildImage({
path,
});
expect(commandResult).to.have.a.property('command', 'docker');
expect(commandResult).to.have.a.property('args').that.deep.equals(
[
escaped('image'),
escaped('build'),
{ value: path, quoting: ShellQuoting.Strong },
]);
});
it('handles pull=true', async () => {
const commandResult = await client.buildImage({
path: '.',
pull: true,
});
expect(commandResult).to.have.property('args').with.lengthOf(4);
});
it('handles pull=false', async () => {
const commandResult = await client.buildImage({
path: '.',
pull: false,
});
expect(commandResult).to.have.property('args').with.lengthOf(3);
});
it('handles file', async () => {
const file = crypto.randomBytes(60).toString('utf8');
const commandResult = await client.buildImage({
path: '.',
file,
});
expect(commandResult).to.have.property('args').that.deep.equals([
escaped('image'),
escaped('build'),
escaped('--file'),
{ value: file, quoting: ShellQuoting.Strong },
{ value: '.', quoting: ShellQuoting.Strong },
]);
});
});
});
describe('DockerClient (unit)', () => {
const client = new DockerClient();
it('Should produce the expected lack of quoting/escaping customOptions', async () => {
const options: BuildImageCommandOptions = {
path: '.',
customOptions: '--no-cache --progress plain'
};
const commandResponse = await client.buildImage(options);
const pwshQuoted = new Powershell().quote(commandResponse.args);
const bashQuoted = new Bash().quote(commandResponse.args);
expect(pwshQuoted).to.deep.equal(['image', 'build', '--no-cache --progress plain', '\'.\'']);
expect(bashQuoted).to.deep.equal(['image', 'build', '--no-cache --progress plain', '\'.\'']);
});
it('Should produce the expected lack of quoting/escaping a single string command', async () => {
const options: RunContainerCommandOptions = {
imageRef: 'someimage',
command: 'sh -c "echo hello world"',
};
const commandResponse = await client.runContainer(options);
const pwshQuoted = new Powershell().quote(commandResponse.args);
const bashQuoted = new Bash().quote(commandResponse.args);
expect(pwshQuoted).to.deep.equal(['container', 'run', 'someimage', 'sh -c "echo hello world"']);
expect(bashQuoted).to.deep.equal(['container', 'run', 'someimage', 'sh -c "echo hello world"']);
});
it('Should produce the expected quoting/escaping of an array command', async () => {
const options: RunContainerCommandOptions = {
imageRef: 'someimage',
command: ['sh', '-c', 'echo hello world'],
};
const commandResponse = await client.runContainer(options);
const pwshQuoted = new Powershell().quote(commandResponse.args);
const bashQuoted = new Bash().quote(commandResponse.args);
expect(pwshQuoted).to.deep.equal(['container', 'run', 'someimage', 'sh', '-c', 'echo` hello` world']);
expect(bashQuoted).to.deep.equal(['container', 'run', 'someimage', 'sh', '-c', 'echo\\ hello\\ world']);
});
});

Просмотреть файл

@ -1,132 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { expect } from 'chai';
import { DockerComposeClient } from '../clients/DockerComposeClient/DockerComposeClient';
import { ShellStreamCommandRunnerFactory } from '../commandRunners/shellStream';
import {
CommonOrchestratorCommandOptions,
ConfigCommandOptions,
DownCommandOptions,
LogsCommandOptions,
RestartCommandOptions,
StartCommandOptions,
StopCommandOptions,
UpCommandOptions
} from '../contracts/ContainerOrchestratorClient';
import { AccumulatorStream } from '../utils/AccumulatorStream';
import { Bash, Cmd, NoShell, Powershell } from '../utils/spawnStreamAsync';
const commonOptions: CommonOrchestratorCommandOptions = {
files: ['docker-compose.yml'],
};
xdescribe('DockerComposeClient', () => {
const client = new DockerComposeClient();
const cwd = 'TODO';
const runnerFactory = new ShellStreamCommandRunnerFactory({
cwd: cwd,
onCommand: (command: string) => { console.log(`Executing ${command}`); },
});
const runner = runnerFactory.getCommandRunner();
it('Should support up command', async () => {
const options: UpCommandOptions = {
...commonOptions,
detached: true,
build: true,
};
await runner(client.up(options));
});
it('Should support stop command', async () => {
const options: StopCommandOptions = {
...commonOptions,
};
await runner(client.stop(options));
});
it('Should support start command', async () => {
const options: StartCommandOptions = {
...commonOptions,
};
await runner(client.start(options));
});
it('Should support restart command', async () => {
const options: RestartCommandOptions = {
...commonOptions,
};
await runner(client.restart(options));
});
it('Should support logs command', async () => {
const options: LogsCommandOptions = {
...commonOptions,
};
const accumulator = new AccumulatorStream();
const logsCRF = new ShellStreamCommandRunnerFactory({
cwd: cwd,
stdOutPipe: accumulator,
onCommand: (command: string) => { console.log(`Executing ${command}`); },
});
await logsCRF.getStreamingCommandRunner()(client.logs(options));
const logs = await accumulator.getString();
expect(logs).to.be.ok;
});
it('Should support down command', async () => {
const options: DownCommandOptions = {
...commonOptions,
};
await runner(client.down(options));
});
it('Should support config command', async () => {
const options: ConfigCommandOptions = {
...commonOptions,
configType: 'services',
};
const result = await runner(client.config(options));
expect(result).to.be.ok;
expect(result).to.contain('registry');
});
});
describe('DockerComposeClient (unit)', () => {
const client = new DockerComposeClient();
client.composeV2 = false;
it('Should produce the expected lack of quoting/escaping customOptions', async () => {
const options: UpCommandOptions = {
...commonOptions,
detached: true,
build: true,
customOptions: '--timeout 10 --wait'
};
const commandResponse = await client.up(options);
const pwshQuoted = new Powershell().quote(commandResponse.args);
const cmdQuoted = new Cmd().quote(commandResponse.args);
const bashQuoted = new Bash().quote(commandResponse.args);
const noShellQuotedWindows = new NoShell(true).quote(commandResponse.args);
const noShellQuotedLinux = new NoShell(false).quote(commandResponse.args);
expect(pwshQuoted).to.deep.equal(['--file', '\'docker-compose.yml\'', 'up', '--detach', '--build', '--timeout 10 --wait']);
expect(cmdQuoted).to.deep.equal(['--file', '"docker-compose.yml"', 'up', '--detach', '--build', '--timeout 10 --wait']);
expect(bashQuoted).to.deep.equal(['--file', '\'docker-compose.yml\'', 'up', '--detach', '--build', '--timeout 10 --wait']);
expect(noShellQuotedWindows).to.deep.equal(['--file', '"docker-compose.yml"', 'up', '--detach', '--build', '--timeout 10 --wait']);
expect(noShellQuotedLinux).to.deep.equal(['--file', 'docker-compose.yml', 'up', '--detach', '--build', '--timeout 10 --wait']);
});
});

Просмотреть файл

@ -1,56 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { expect } from 'chai';
import * as crypto from 'crypto';
import { describe, it } from 'mocha';
import { ShellQuotedString, ShellQuoting } from 'vscode';
import { range } from '../utils/range';
import {
escaped,
quoted,
withArg,
} from '../utils/commandLineBuilder';
describe('commandLineBuilder', () => {
describe('#withArg()', () => {
it('creates arg list if no initial args provided', () => {
const arg = crypto.randomBytes(crypto.randomInt(20, 101)).toString('utf8');
const args = withArg(quoted(arg))();
expect(args).to.have.lengthOf(1);
expect(args).to.deep.equal([quoted(arg)]);
});
it('creates arg list if empty initial args provided', () => {
const arg = crypto.randomBytes(crypto.randomInt(20, 101)).toString('utf8');
const args = withArg(arg)([]);
expect(args).to.have.lengthOf(1);
expect(args).to.deep.equal([escaped(arg)]);
});
it('appends to initial arg list', () => {
const initialArgs = new Array<ShellQuotedString>({ value: 'first', quoting: ShellQuoting.Escape }, { value: 'second', quoting: ShellQuoting.Strong });
const newArgsCount = crypto.randomInt(1, 5);
const newArgs: Array<ShellQuotedString> = [...range(newArgsCount)].map(() => {
return { value: crypto.randomBytes(crypto.randomInt(20, 101)).toString('utf8'), quoting: ShellQuoting.Weak };
});
const args = withArg(...newArgs)(initialArgs);
expect(initialArgs).to.have.lengthOf(2);
expect(args).to.have.lengthOf(2 + newArgsCount);
expect(args).to.deep.equal([...initialArgs, ...newArgs]);
});
it("doesn't append empty args", () => {
const initialArgs = new Array<ShellQuotedString>({ value: 'first', quoting: ShellQuoting.Escape }, { value: 'second', quoting: ShellQuoting.Strong });
const newArgs = ['third', '', 'fifth'];
const args = withArg(...newArgs)(initialArgs);
expect(initialArgs).to.have.lengthOf(2);
expect(args).to.have.lengthOf(4);
expect(args).to.deep.equal([...initialArgs, escaped('third'), escaped('fifth')]);
});
});
});

Просмотреть файл

@ -1,35 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { expect } from 'chai';
import { describe, it } from 'mocha';
import { normalizeContainerState } from '../clients/DockerClientBase/DockerListContainerRecord';
describe('normalizeContainerState', () => {
it('Should use the state if it is present', () => {
expect(normalizeContainerState({ State: 'running', Status: 'Ignore' })).to.equal('running');
expect(normalizeContainerState({ State: 'exited', Status: 'Ignore' })).to.equal('exited');
expect(normalizeContainerState({ State: 'paused', Status: 'Ignore' })).to.equal('paused');
expect(normalizeContainerState({ State: 'fake', Status: 'Ignore' })).to.equal('fake');
});
it('Should use the status if the state is not present', () => {
expect(normalizeContainerState({ Status: 'Up 2 minutes (Paused)' })).to.equal('paused');
expect(normalizeContainerState({ Status: 'Up 2 minutes' })).to.equal('running');
expect(normalizeContainerState({ Status: 'Exited (0) 2 minutes ago' })).to.equal('exited');
expect(normalizeContainerState({ Status: 'Terminated (1) 2 minutes ago' })).to.equal('exited');
expect(normalizeContainerState({ Status: 'Dead' })).to.equal('exited');
expect(normalizeContainerState({ Status: 'Created' })).to.equal('created');
});
it('Should return state unknown if the status is unrecognized', () => {
expect(normalizeContainerState({ Status: 'Foo' })).to.equal('unknown');
});
});

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше